Complete integration of original OSCPack lib

This commit is contained in:
brunoherbelin
2020-10-20 18:18:44 +02:00
parent 27239b7513
commit 65aefc9fb8
25 changed files with 4429 additions and 3142 deletions

View File

@@ -152,11 +152,19 @@ message(STATUS "Compiling 'TinyXML2' from https://github.com/leethomason/tinyxml
# #
# OSCPack # OSCPack
# #
if(UNIX)
set(OSCPACK_PLATFORM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/ip/posix/)
elseif(WIN32)
set(OSCPACK_PLATFORM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/ip/win32/)
endif()
set(OSCPACK_SRCS set(OSCPACK_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/OscTypes.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/osc/OscTypes.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/OscReceivedElements.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/osc/OscReceivedElements.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/OscPrintReceivedElements.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/osc/OscPrintReceivedElements.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/OscOutboundPacketStream.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/osc/OscOutboundPacketStream.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/ip/IpEndpointName.cpp
${OSCPACK_PLATFORM_DIR}/NetworkingUtils.cpp
${OSCPACK_PLATFORM_DIR}/UdpSocket.cpp
) )
set(OSCPACK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack) set(OSCPACK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack)
add_library(OSCPACK "${OSCPACK_SRCS}") add_library(OSCPACK "${OSCPACK_SRCS}")
@@ -218,7 +226,7 @@ include_directories(
${TINYFD_INCLUDE_DIR} ${TINYFD_INCLUDE_DIR}
${STB_INCLUDE_DIR} ${STB_INCLUDE_DIR}
${DIRENT_INCLUDE_DIR} ${DIRENT_INCLUDE_DIR}
${OBJLOADER_INCLUDE_DIR} ${OSCPACK_INCLUDE_DIR}
) )

View File

@@ -1,127 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H
#define INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H
/*
Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined
We try to use preprocessor symbols to deduce the host endianness.
Alternatively you can define one of the above symbols from the command line.
Usually you do this with the -D flag to the compiler. e.g.:
$ g++ -DOSC_HOST_LITTLE_ENDIAN ...
*/
#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN)
// endianness defined on the command line. nothing to do here.
#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE)
// assume that __WIN32__ is only defined on little endian systems
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif defined(__APPLE__)
#if defined(__LITTLE_ENDIAN__)
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif defined(__BIG_ENDIAN__)
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
// should cover gcc and clang
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#else
// gcc defines __LITTLE_ENDIAN__ and __BIG_ENDIAN__
// for others used here see http://sourceforge.net/p/predef/wiki/Endianness/
#if (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \
|| (defined(__ARMEL__) && !defined(__ARMEB__)) \
|| (defined(__AARCH64EL__) && !defined(__AARCH64EB__)) \
|| (defined(_MIPSEL) && !defined(_MIPSEB)) \
|| (defined(__MIPSEL) && !defined(__MIPSEB)) \
|| (defined(__MIPSEL__) && !defined(__MIPSEB__))
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \
|| (defined(__ARMEB__) && !defined(__ARMEL__)) \
|| (defined(__AARCH64EB__) && !defined(__AARCH64EL__)) \
|| (defined(_MIPSEB) && !defined(_MIPSEL)) \
|| (defined(__MIPSEB) && !defined(__MIPSEL)) \
|| (defined(__MIPSEB__) && !defined(__MIPSEL__))
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#endif
#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN)
#error please edit OSCHostEndianness.h or define one of {OSC_HOST_LITTLE_ENDIAN, OSC_HOST_BIG_ENDIAN} to configure endianness
#endif
#endif /* INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H */

View File

@@ -1,797 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscReceivedElements.h"
#include "OscHostEndianness.h"
#include <cstddef> // ptrdiff_t
namespace osc{
// return the first 4 byte boundary after the end of a str4
// be careful about calling this version if you don't know whether
// the string is terminated correctly.
static inline const char* FindStr4End( const char *p )
{
if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
return p + 4;
p += 3;
while( *p )
p += 4;
return p + 1;
}
// return the first 4 byte boundary after the end of a str4
// returns 0 if p == end or if the string is unterminated
static inline const char* FindStr4End( const char *p, const char *end )
{
if( p >= end )
return 0;
if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
return p + 4;
p += 3;
end -= 1;
while( p < end && *p )
p += 4;
if( *p )
return 0;
else
return p + 1;
}
// round up to the next highest multiple of 4. unless x is already a multiple of 4
static inline uint32 RoundUp4( uint32 x )
{
return (x + 3) & ~((uint32)0x03);
}
static inline int32 ToInt32( const char *p )
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::int32 i;
char c[4];
} u;
u.c[0] = p[3];
u.c[1] = p[2];
u.c[2] = p[1];
u.c[3] = p[0];
return u.i;
#else
return *(int32*)p;
#endif
}
static inline uint32 ToUInt32( const char *p )
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::uint32 i;
char c[4];
} u;
u.c[0] = p[3];
u.c[1] = p[2];
u.c[2] = p[1];
u.c[3] = p[0];
return u.i;
#else
return *(uint32*)p;
#endif
}
static inline int64 ToInt64( const char *p )
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::int64 i;
char c[8];
} u;
u.c[0] = p[7];
u.c[1] = p[6];
u.c[2] = p[5];
u.c[3] = p[4];
u.c[4] = p[3];
u.c[5] = p[2];
u.c[6] = p[1];
u.c[7] = p[0];
return u.i;
#else
return *(int64*)p;
#endif
}
static inline uint64 ToUInt64( const char *p )
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::uint64 i;
char c[8];
} u;
u.c[0] = p[7];
u.c[1] = p[6];
u.c[2] = p[5];
u.c[3] = p[4];
u.c[4] = p[3];
u.c[5] = p[2];
u.c[6] = p[1];
u.c[7] = p[0];
return u.i;
#else
return *(uint64*)p;
#endif
}
//------------------------------------------------------------------------------
bool ReceivedPacket::IsBundle() const
{
return (Size() > 0 && Contents()[0] == '#');
}
//------------------------------------------------------------------------------
bool ReceivedBundleElement::IsBundle() const
{
return (Size() > 0 && Contents()[0] == '#');
}
osc_bundle_element_size_t ReceivedBundleElement::Size() const
{
return ToInt32( sizePtr_ );
}
//------------------------------------------------------------------------------
bool ReceivedMessageArgument::AsBool() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == TRUE_TYPE_TAG )
return true;
else if( *typeTagPtr_ == FALSE_TYPE_TAG )
return false;
else
throw WrongArgumentTypeException();
}
bool ReceivedMessageArgument::AsBoolUnchecked() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == TRUE_TYPE_TAG )
return true;
else
return false;
}
int32 ReceivedMessageArgument::AsInt32() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == INT32_TYPE_TAG )
return AsInt32Unchecked();
else
throw WrongArgumentTypeException();
}
int32 ReceivedMessageArgument::AsInt32Unchecked() const
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::int32 i;
char c[4];
} u;
u.c[0] = argumentPtr_[3];
u.c[1] = argumentPtr_[2];
u.c[2] = argumentPtr_[1];
u.c[3] = argumentPtr_[0];
return u.i;
#else
return *(int32*)argument_;
#endif
}
float ReceivedMessageArgument::AsFloat() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == FLOAT_TYPE_TAG )
return AsFloatUnchecked();
else
throw WrongArgumentTypeException();
}
float ReceivedMessageArgument::AsFloatUnchecked() const
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
float f;
char c[4];
} u;
u.c[0] = argumentPtr_[3];
u.c[1] = argumentPtr_[2];
u.c[2] = argumentPtr_[1];
u.c[3] = argumentPtr_[0];
return u.f;
#else
return *(float*)argument_;
#endif
}
char ReceivedMessageArgument::AsChar() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == CHAR_TYPE_TAG )
return AsCharUnchecked();
else
throw WrongArgumentTypeException();
}
char ReceivedMessageArgument::AsCharUnchecked() const
{
return (char)ToInt32( argumentPtr_ );
}
uint32 ReceivedMessageArgument::AsRgbaColor() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == RGBA_COLOR_TYPE_TAG )
return AsRgbaColorUnchecked();
else
throw WrongArgumentTypeException();
}
uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
{
return ToUInt32( argumentPtr_ );
}
uint32 ReceivedMessageArgument::AsMidiMessage() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG )
return AsMidiMessageUnchecked();
else
throw WrongArgumentTypeException();
}
uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
{
return ToUInt32( argumentPtr_ );
}
int64 ReceivedMessageArgument::AsInt64() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == INT64_TYPE_TAG )
return AsInt64Unchecked();
else
throw WrongArgumentTypeException();
}
int64 ReceivedMessageArgument::AsInt64Unchecked() const
{
return ToInt64( argumentPtr_ );
}
uint64 ReceivedMessageArgument::AsTimeTag() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == TIME_TAG_TYPE_TAG )
return AsTimeTagUnchecked();
else
throw WrongArgumentTypeException();
}
uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
{
return ToUInt64( argumentPtr_ );
}
double ReceivedMessageArgument::AsDouble() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == DOUBLE_TYPE_TAG )
return AsDoubleUnchecked();
else
throw WrongArgumentTypeException();
}
double ReceivedMessageArgument::AsDoubleUnchecked() const
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
double d;
char c[8];
} u;
u.c[0] = argumentPtr_[7];
u.c[1] = argumentPtr_[6];
u.c[2] = argumentPtr_[5];
u.c[3] = argumentPtr_[4];
u.c[4] = argumentPtr_[3];
u.c[5] = argumentPtr_[2];
u.c[6] = argumentPtr_[1];
u.c[7] = argumentPtr_[0];
return u.d;
#else
return *(double*)argument_;
#endif
}
const char* ReceivedMessageArgument::AsString() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == STRING_TYPE_TAG )
return argumentPtr_;
else
throw WrongArgumentTypeException();
}
const char* ReceivedMessageArgument::AsSymbol() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == SYMBOL_TYPE_TAG )
return argumentPtr_;
else
throw WrongArgumentTypeException();
}
void ReceivedMessageArgument::AsBlob( const void*& data, osc_bundle_element_size_t& size ) const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == BLOB_TYPE_TAG )
AsBlobUnchecked( data, size );
else
throw WrongArgumentTypeException();
}
void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const
{
// read blob size as an unsigned int then validate
osc_bundle_element_size_t sizeResult = (osc_bundle_element_size_t)ToUInt32( argumentPtr_ );
if( !IsValidElementSizeValue(sizeResult) )
throw MalformedMessageException("invalid blob size");
size = sizeResult;
data = (void*)(argumentPtr_+ osc::OSC_SIZEOF_INT32);
}
std::size_t ReceivedMessageArgument::ComputeArrayItemCount() const
{
// it is only valid to call ComputeArrayItemCount when the argument is the array start marker
if( !IsArrayBegin() )
throw WrongArgumentTypeException();
std::size_t result = 0;
unsigned int level = 0;
const char *typeTag = typeTagPtr_ + 1;
// iterate through all type tags. note that ReceivedMessage::Init
// has already checked that the message is well formed.
while( *typeTag ) {
switch( *typeTag++ ) {
case ARRAY_BEGIN_TYPE_TAG:
level += 1;
break;
case ARRAY_END_TYPE_TAG:
if(level == 0)
return result;
level -= 1;
break;
default:
if( level == 0 ) // only count items at level 0
++result;
}
}
return result;
}
//------------------------------------------------------------------------------
void ReceivedMessageArgumentIterator::Advance()
{
if( !value_.typeTagPtr_ )
return;
switch( *value_.typeTagPtr_++ ){
case '\0':
// don't advance past end
--value_.typeTagPtr_;
break;
case TRUE_TYPE_TAG:
case FALSE_TYPE_TAG:
case NIL_TYPE_TAG:
case INFINITUM_TYPE_TAG:
// zero length
break;
case INT32_TYPE_TAG:
case FLOAT_TYPE_TAG:
case CHAR_TYPE_TAG:
case RGBA_COLOR_TYPE_TAG:
case MIDI_MESSAGE_TYPE_TAG:
value_.argumentPtr_ += 4;
break;
case INT64_TYPE_TAG:
case TIME_TAG_TYPE_TAG:
case DOUBLE_TYPE_TAG:
value_.argumentPtr_ += 8;
break;
case STRING_TYPE_TAG:
case SYMBOL_TYPE_TAG:
// we use the unsafe function FindStr4End(char*) here because all of
// the arguments have already been validated in
// ReceivedMessage::Init() below.
value_.argumentPtr_ = FindStr4End( value_.argumentPtr_ );
break;
case BLOB_TYPE_TAG:
{
// treat blob size as an unsigned int for the purposes of this calculation
uint32 blobSize = ToUInt32( value_.argumentPtr_ );
value_.argumentPtr_ = value_.argumentPtr_ + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize );
}
break;
case ARRAY_BEGIN_TYPE_TAG:
case ARRAY_END_TYPE_TAG:
// [ Indicates the beginning of an array. The tags following are for
// data in the Array until a close brace tag is reached.
// ] Indicates the end of an array.
// zero length, don't advance argument ptr
break;
default: // unknown type tag
// don't advance
--value_.typeTagPtr_;
break;
}
}
//------------------------------------------------------------------------------
ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )
: addressPattern_( packet.Contents() )
{
Init( packet.Contents(), packet.Size() );
}
ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
: addressPattern_( bundleElement.Contents() )
{
Init( bundleElement.Contents(), bundleElement.Size() );
}
bool ReceivedMessage::AddressPatternIsUInt32() const
{
return (addressPattern_[0] == '\0');
}
uint32 ReceivedMessage::AddressPatternAsUInt32() const
{
return ToUInt32( addressPattern_ );
}
void ReceivedMessage::Init( const char *message, osc_bundle_element_size_t size )
{
if( !IsValidElementSizeValue(size) )
throw MalformedMessageException( "invalid message size" );
if( size == 0 )
throw MalformedMessageException( "zero length messages not permitted" );
if( !IsMultipleOf4(size) )
throw MalformedMessageException( "message size must be multiple of four" );
const char *end = message + size;
typeTagsBegin_ = FindStr4End( addressPattern_, end );
if( typeTagsBegin_ == 0 ){
// address pattern was not terminated before end
throw MalformedMessageException( "unterminated address pattern" );
}
if( typeTagsBegin_ == end ){
// message consists of only the address pattern - no arguments or type tags.
typeTagsBegin_ = 0;
typeTagsEnd_ = 0;
arguments_ = 0;
}else{
if( *typeTagsBegin_ != ',' )
throw MalformedMessageException( "type tags not present" );
if( *(typeTagsBegin_ + 1) == '\0' ){
// zero length type tags
typeTagsBegin_ = 0;
typeTagsEnd_ = 0;
arguments_ = 0;
}else{
// check that all arguments are present and well formed
arguments_ = FindStr4End( typeTagsBegin_, end );
if( arguments_ == 0 ){
throw MalformedMessageException( "type tags were not terminated before end of message" );
}
++typeTagsBegin_; // advance past initial ','
const char *typeTag = typeTagsBegin_;
const char *argument = arguments_;
unsigned int arrayLevel = 0;
do{
switch( *typeTag ){
case TRUE_TYPE_TAG:
case FALSE_TYPE_TAG:
case NIL_TYPE_TAG:
case INFINITUM_TYPE_TAG:
// zero length
break;
// [ Indicates the beginning of an array. The tags following are for
// data in the Array until a close brace tag is reached.
// ] Indicates the end of an array.
case ARRAY_BEGIN_TYPE_TAG:
++arrayLevel;
// (zero length argument data)
break;
case ARRAY_END_TYPE_TAG:
--arrayLevel;
// (zero length argument data)
break;
case INT32_TYPE_TAG:
case FLOAT_TYPE_TAG:
case CHAR_TYPE_TAG:
case RGBA_COLOR_TYPE_TAG:
case MIDI_MESSAGE_TYPE_TAG:
if( argument == end )
throw MalformedMessageException( "arguments exceed message size" );
argument += 4;
if( argument > end )
throw MalformedMessageException( "arguments exceed message size" );
break;
case INT64_TYPE_TAG:
case TIME_TAG_TYPE_TAG:
case DOUBLE_TYPE_TAG:
if( argument == end )
throw MalformedMessageException( "arguments exceed message size" );
argument += 8;
if( argument > end )
throw MalformedMessageException( "arguments exceed message size" );
break;
case STRING_TYPE_TAG:
case SYMBOL_TYPE_TAG:
if( argument == end )
throw MalformedMessageException( "arguments exceed message size" );
argument = FindStr4End( argument, end );
if( argument == 0 )
throw MalformedMessageException( "unterminated string argument" );
break;
case BLOB_TYPE_TAG:
{
if( argument + osc::OSC_SIZEOF_INT32 > end )
MalformedMessageException( "arguments exceed message size" );
// treat blob size as an unsigned int for the purposes of this calculation
uint32 blobSize = ToUInt32( argument );
argument = argument + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize );
if( argument > end )
MalformedMessageException( "arguments exceed message size" );
}
break;
default:
throw MalformedMessageException( "unknown type tag" );
}
}while( *++typeTag != '\0' );
typeTagsEnd_ = typeTag;
if( arrayLevel != 0 )
throw MalformedMessageException( "array was not terminated before end of message (expected ']' end of array tag)" );
}
// These invariants should be guaranteed by the above code.
// we depend on them in the implementation of ArgumentCount()
#ifndef NDEBUG
std::ptrdiff_t argumentCount = typeTagsEnd_ - typeTagsBegin_;
assert( argumentCount >= 0 );
assert( argumentCount <= OSC_INT32_MAX );
#endif
}
}
//------------------------------------------------------------------------------
ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )
: elementCount_( 0 )
{
Init( packet.Contents(), packet.Size() );
}
ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
: elementCount_( 0 )
{
Init( bundleElement.Contents(), bundleElement.Size() );
}
void ReceivedBundle::Init( const char *bundle, osc_bundle_element_size_t size )
{
if( !IsValidElementSizeValue(size) )
throw MalformedBundleException( "invalid bundle size" );
if( size < 16 )
throw MalformedBundleException( "packet too short for bundle" );
if( !IsMultipleOf4(size) )
throw MalformedBundleException( "bundle size must be multiple of four" );
if( bundle[0] != '#'
|| bundle[1] != 'b'
|| bundle[2] != 'u'
|| bundle[3] != 'n'
|| bundle[4] != 'd'
|| bundle[5] != 'l'
|| bundle[6] != 'e'
|| bundle[7] != '\0' )
throw MalformedBundleException( "bad bundle address pattern" );
end_ = bundle + size;
timeTag_ = bundle + 8;
const char *p = timeTag_ + 8;
while( p < end_ ){
if( p + osc::OSC_SIZEOF_INT32 > end_ )
throw MalformedBundleException( "packet too short for elementSize" );
// treat element size as an unsigned int for the purposes of this calculation
uint32 elementSize = ToUInt32( p );
if( (elementSize & ((uint32)0x03)) != 0 )
throw MalformedBundleException( "bundle element size must be multiple of four" );
p += osc::OSC_SIZEOF_INT32 + elementSize;
if( p > end_ )
throw MalformedBundleException( "packet too short for bundle element" );
++elementCount_;
}
if( p != end_ )
throw MalformedBundleException( "bundle contents " );
}
uint64 ReceivedBundle::TimeTag() const
{
return ToUInt64( timeTag_ );
}
} // namespace osc

View File

@@ -0,0 +1,81 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "IpEndpointName.h"
#include <stdio.h>
#include "NetworkingUtils.h"
unsigned long IpEndpointName::GetHostByName( const char *s )
{
return ::GetHostByName(s);
}
void IpEndpointName::AddressAsString( char *s ) const
{
if( address == ANY_ADDRESS ){
sprintf( s, "<any>" );
}else{
sprintf( s, "%d.%d.%d.%d",
(int)((address >> 24) & 0xFF),
(int)((address >> 16) & 0xFF),
(int)((address >> 8) & 0xFF),
(int)(address & 0xFF) );
}
}
void IpEndpointName::AddressAndPortAsString( char *s ) const
{
if( port == ANY_PORT ){
if( address == ANY_ADDRESS ){
sprintf( s, "<any>:<any>" );
}else{
sprintf( s, "%d.%d.%d.%d:<any>",
(int)((address >> 24) & 0xFF),
(int)((address >> 16) & 0xFF),
(int)((address >> 8) & 0xFF),
(int)(address & 0xFF) );
}
}else{
if( address == ANY_ADDRESS ){
sprintf( s, "<any>:%d", port );
}else{
sprintf( s, "%d.%d.%d.%d:%d",
(int)((address >> 24) & 0xFF),
(int)((address >> 16) & 0xFF),
(int)((address >> 8) & 0xFF),
(int)(address & 0xFF),
(int)port );
}
}
}

View File

@@ -0,0 +1,74 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef INCLUDED_IPENDPOINTNAME_H
#define INCLUDED_IPENDPOINTNAME_H
class IpEndpointName{
static unsigned long GetHostByName( const char *s );
public:
static const unsigned long ANY_ADDRESS = 0xFFFFFFFF;
static const int ANY_PORT = -1;
IpEndpointName()
: address( ANY_ADDRESS ), port( ANY_PORT ) {}
IpEndpointName( int port_ )
: address( ANY_ADDRESS ), port( port_ ) {}
IpEndpointName( unsigned long ipAddress_, int port_ )
: address( ipAddress_ ), port( port_ ) {}
IpEndpointName( const char *addressName, int port_=ANY_PORT )
: address( GetHostByName( addressName ) )
, port( port_ ) {}
IpEndpointName( int addressA, int addressB, int addressC, int addressD, int port_=ANY_PORT )
: address( ( (addressA << 24) | (addressB << 16) | (addressC << 8) | addressD ) )
, port( port_ ) {}
// address and port are maintained in host byte order here
unsigned long address;
int port;
enum { ADDRESS_STRING_LENGTH=17 };
void AddressAsString( char *s ) const;
enum { ADDRESS_AND_PORT_STRING_LENGTH=23};
void AddressAndPortAsString( char *s ) const;
};
inline bool operator==( const IpEndpointName& lhs, const IpEndpointName& rhs )
{
return (lhs.address == rhs.address && lhs.port == rhs.port );
}
inline bool operator!=( const IpEndpointName& lhs, const IpEndpointName& rhs )
{
return !(lhs == rhs);
}
#endif /* INCLUDED_IPENDPOINTNAME_H */

View File

@@ -0,0 +1,49 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef INCLUDED_NETWORKINGUTILS_H
#define INCLUDED_NETWORKINGUTILS_H
// in general NetworkInitializer is only used internally, but if you're
// application creates multiple sockets from different threads at runtime you
// should instantiate one of these in main just to make sure the networking
// layer is initialized.
class NetworkInitializer{
public:
NetworkInitializer();
~NetworkInitializer();
};
// return ip address of host name in host byte order
unsigned long GetHostByName( const char *name );
#endif /* INCLUDED_NETWORKINGUTILS_H */

View File

@@ -0,0 +1,43 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef INCLUDED_PACKETLISTENER_H
#define INCLUDED_PACKETLISTENER_H
class IpEndpointName;
class PacketListener{
public:
virtual ~PacketListener() {}
virtual void ProcessPacket( const char *data, int size,
const IpEndpointName& remoteEndpoint ) = 0;
};
#endif /* INCLUDED_PACKETLISTENER_H */

View File

@@ -0,0 +1,40 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef INCLUDED_TIMERLISTENER_H
#define INCLUDED_TIMERLISTENER_H
class TimerListener{
public:
virtual ~TimerListener() {}
virtual void TimerExpired() = 0;
};
#endif /* INCLUDED_TIMERLISTENER_H */

158
ext/OSCPack/ip/UdpSocket.h Normal file
View File

@@ -0,0 +1,158 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef INCLUDED_UDPSOCKET_H
#define INCLUDED_UDPSOCKET_H
#ifndef INCLUDED_NETWORKINGUTILITIES_H
#include "NetworkingUtils.h"
#endif /* INCLUDED_NETWORKINGUTILITIES_H */
#ifndef INCLUDED_IPENDPOINTNAME_H
#include "IpEndpointName.h"
#endif /* INCLUDED_IPENDPOINTNAME_H */
class PacketListener;
class TimerListener;
class UdpSocket;
class SocketReceiveMultiplexer{
class Implementation;
Implementation *impl_;
friend class UdpSocket;
public:
SocketReceiveMultiplexer();
~SocketReceiveMultiplexer();
// only call the attach/detach methods _before_ calling Run
// only one listener per socket, each socket at most once
void AttachSocketListener( UdpSocket *socket, PacketListener *listener );
void DetachSocketListener( UdpSocket *socket, PacketListener *listener );
void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener );
void AttachPeriodicTimerListener(
int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener );
void DetachPeriodicTimerListener( TimerListener *listener );
void Run(); // loop and block processing messages indefinitely
void RunUntilSigInt();
void Break(); // call this from a listener to exit once the listener returns
void AsynchronousBreak(); // call this from another thread or signal handler to exit the Run() state
};
class UdpSocket{
class Implementation;
Implementation *impl_;
friend class SocketReceiveMultiplexer::Implementation;
public:
// ctor throws std::runtime_error if there's a problem
// initializing the socket.
UdpSocket();
virtual ~UdpSocket();
// the socket is created in an unbound, unconnected state
// such a socket can only be used to send to an arbitrary
// address using SendTo(). To use Send() you need to first
// connect to a remote endpoint using Connect(). To use
// ReceiveFrom you need to first bind to a local endpoint
// using Bind().
// retrieve the local endpoint name when sending to 'to'
IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const;
// Connect to a remote endpoint which is used as the target
// for calls to Send()
void Connect( const IpEndpointName& remoteEndpoint );
void Send( const char *data, int size );
void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size );
// Bind a local endpoint to receive incoming data. Endpoint
// can be 'any' for the system to choose an endpoint
void Bind( const IpEndpointName& localEndpoint );
bool IsBound() const;
int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size );
};
// convenience classes for transmitting and receiving
// they just call Connect and/or Bind in the ctor.
// note that you can still use a receive socket
// for transmitting etc
class UdpTransmitSocket : public UdpSocket{
public:
UdpTransmitSocket( const IpEndpointName& remoteEndpoint )
{ Connect( remoteEndpoint ); }
};
class UdpReceiveSocket : public UdpSocket{
public:
UdpReceiveSocket( const IpEndpointName& localEndpoint )
{ Bind( localEndpoint ); }
};
// UdpListeningReceiveSocket provides a simple way to bind one listener
// to a single socket without having to manually set up a SocketReceiveMultiplexer
class UdpListeningReceiveSocket : public UdpSocket{
SocketReceiveMultiplexer mux_;
PacketListener *listener_;
public:
UdpListeningReceiveSocket( const IpEndpointName& localEndpoint, PacketListener *listener )
: listener_( listener )
{
Bind( localEndpoint );
mux_.AttachSocketListener( this, listener_ );
}
~UdpListeningReceiveSocket()
{ mux_.DetachSocketListener( this, listener_ ); }
// see SocketReceiveMultiplexer above for the behaviour of these methods...
void Run() { mux_.Run(); }
void RunUntilSigInt() { mux_.RunUntilSigInt(); }
void Break() { mux_.Break(); }
void AsynchronousBreak() { mux_.AsynchronousBreak(); }
};
#endif /* INCLUDED_UDPSOCKET_H */

View File

@@ -0,0 +1,57 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ip/NetworkingUtils.h"
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
NetworkInitializer::NetworkInitializer() {}
NetworkInitializer::~NetworkInitializer() {}
unsigned long GetHostByName( const char *name )
{
unsigned long result = 0;
struct hostent *h = gethostbyname( name );
if( h ){
struct in_addr a;
memcpy( &a, h->h_addr_list[0], h->h_length );
result = ntohl(a.s_addr);
}
return result;
}

View File

@@ -0,0 +1,546 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ip/UdpSocket.h"
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <assert.h>
#include <signal.h>
#include <math.h>
#include <errno.h>
#include <string.h> // for memset
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h> // for sockaddr_in
#include "ip/PacketListener.h"
#include "ip/TimerListener.h"
#if defined(__APPLE__) && !defined(_SOCKLEN_T)
// pre system 10.3 didn have socklen_t
typedef ssize_t socklen_t;
#endif
static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint )
{
memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr =
(endpoint.address == IpEndpointName::ANY_ADDRESS)
? INADDR_ANY
: htonl( endpoint.address );
sockAddr.sin_port =
(endpoint.port == IpEndpointName::ANY_PORT)
? 0
: htons( endpoint.port );
}
static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr )
{
return IpEndpointName(
(sockAddr.sin_addr.s_addr == INADDR_ANY)
? IpEndpointName::ANY_ADDRESS
: ntohl( sockAddr.sin_addr.s_addr ),
(sockAddr.sin_port == 0)
? IpEndpointName::ANY_PORT
: ntohs( sockAddr.sin_port )
);
}
class UdpSocket::Implementation{
bool isBound_;
bool isConnected_;
int socket_;
struct sockaddr_in connectedAddr_;
struct sockaddr_in sendToAddr_;
public:
Implementation()
: isBound_( false )
, isConnected_( false )
, socket_( -1 )
{
if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 ){
throw std::runtime_error("unable to create udp socket\n");
}
memset( &sendToAddr_, 0, sizeof(sendToAddr_) );
sendToAddr_.sin_family = AF_INET;
}
~Implementation()
{
if (socket_ != -1) close(socket_);
}
IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
{
assert( isBound_ );
// first connect the socket to the remote server
struct sockaddr_in connectSockAddr;
SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint );
if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) {
throw std::runtime_error("unable to connect udp socket\n");
}
// get the address
struct sockaddr_in sockAddr;
memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
socklen_t length = sizeof(sockAddr);
if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) {
throw std::runtime_error("unable to getsockname\n");
}
if( isConnected_ ){
// reconnect to the connected address
if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
throw std::runtime_error("unable to connect udp socket\n");
}
}else{
// unconnect from the remote address
struct sockaddr_in unconnectSockAddr;
memset( (char *)&unconnectSockAddr, 0, sizeof(unconnectSockAddr ) );
unconnectSockAddr.sin_family = AF_UNSPEC;
// address fields are zero
int connectResult = connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr));
if ( connectResult < 0 && errno != EAFNOSUPPORT ) {
throw std::runtime_error("unable to un-connect udp socket\n");
}
}
return IpEndpointNameFromSockaddr( sockAddr );
}
void Connect( const IpEndpointName& remoteEndpoint )
{
SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint );
if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
throw std::runtime_error("unable to connect udp socket\n");
}
isConnected_ = true;
}
void Send( const char *data, int size )
{
assert( isConnected_ );
send( socket_, data, size, 0 );
}
void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size )
{
sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address );
sendToAddr_.sin_port = htons( remoteEndpoint.port );
sendto( socket_, data, size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) );
}
void Bind( const IpEndpointName& localEndpoint )
{
struct sockaddr_in bindSockAddr;
SockaddrFromIpEndpointName( bindSockAddr, localEndpoint );
if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) {
throw std::runtime_error("unable to bind udp socket\n");
}
isBound_ = true;
}
bool IsBound() const { return isBound_; }
int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size )
{
assert( isBound_ );
struct sockaddr_in fromAddr;
socklen_t fromAddrLen = sizeof(fromAddr);
int result = recvfrom(socket_, data, size, 0,
(struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen);
if( result < 0 )
return 0;
remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr);
remoteEndpoint.port = ntohs(fromAddr.sin_port);
return result;
}
int Socket() { return socket_; }
};
UdpSocket::UdpSocket()
{
impl_ = new Implementation();
}
UdpSocket::~UdpSocket()
{
delete impl_;
}
IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
{
return impl_->LocalEndpointFor( remoteEndpoint );
}
void UdpSocket::Connect( const IpEndpointName& remoteEndpoint )
{
impl_->Connect( remoteEndpoint );
}
void UdpSocket::Send( const char *data, int size )
{
impl_->Send( data, size );
}
void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size )
{
impl_->SendTo( remoteEndpoint, data, size );
}
void UdpSocket::Bind( const IpEndpointName& localEndpoint )
{
impl_->Bind( localEndpoint );
}
bool UdpSocket::IsBound() const
{
return impl_->IsBound();
}
int UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size )
{
return impl_->ReceiveFrom( remoteEndpoint, data, size );
}
struct AttachedTimerListener{
AttachedTimerListener( int id, int p, TimerListener *tl )
: initialDelayMs( id )
, periodMs( p )
, listener( tl ) {}
int initialDelayMs;
int periodMs;
TimerListener *listener;
};
static bool CompareScheduledTimerCalls(
const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs )
{
return lhs.first < rhs.first;
}
SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0;
extern "C" /*static*/ void InterruptSignalHandler( int );
/*static*/ void InterruptSignalHandler( int )
{
multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak();
signal( SIGINT, SIG_DFL );
}
class SocketReceiveMultiplexer::Implementation{
std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_;
std::vector< AttachedTimerListener > timerListeners_;
volatile bool break_;
int breakPipe_[2]; // [0] is the reader descriptor and [1] the writer
double GetCurrentTimeMs() const
{
struct timeval t;
gettimeofday( &t, 0 );
return ((double)t.tv_sec*1000.) + ((double)t.tv_usec / 1000.);
}
public:
Implementation()
{
if( pipe(breakPipe_) != 0 )
throw std::runtime_error( "creation of asynchronous break pipes failed\n" );
}
~Implementation()
{
close( breakPipe_[0] );
close( breakPipe_[1] );
}
void AttachSocketListener( UdpSocket *socket, PacketListener *listener )
{
assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() );
// we don't check that the same socket has been added multiple times, even though this is an error
socketListeners_.push_back( std::make_pair( listener, socket ) );
}
void DetachSocketListener( UdpSocket *socket, PacketListener *listener )
{
std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i =
std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) );
assert( i != socketListeners_.end() );
socketListeners_.erase( i );
}
void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
{
timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) );
}
void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
{
timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) );
}
void DetachPeriodicTimerListener( TimerListener *listener )
{
std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
while( i != timerListeners_.end() ){
if( i->listener == listener )
break;
++i;
}
assert( i != timerListeners_.end() );
timerListeners_.erase( i );
}
void Run()
{
break_ = false;
// configure the master fd_set for select()
fd_set masterfds, tempfds;
FD_ZERO( &masterfds );
FD_ZERO( &tempfds );
// in addition to listening to the inbound sockets we
// also listen to the asynchronous break pipe, so that AsynchronousBreak()
// can break us out of select() from another thread.
FD_SET( breakPipe_[0], &masterfds );
int fdmax = breakPipe_[0];
for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
i != socketListeners_.end(); ++i ){
if( fdmax < i->second->impl_->Socket() )
fdmax = i->second->impl_->Socket();
FD_SET( i->second->impl_->Socket(), &masterfds );
}
// configure the timer queue
double currentTimeMs = GetCurrentTimeMs();
// expiry time ms, listener
std::vector< std::pair< double, AttachedTimerListener > > timerQueue_;
for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
i != timerListeners_.end(); ++i )
timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) );
std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
const int MAX_BUFFER_SIZE = 4098;
char *data = new char[ MAX_BUFFER_SIZE ];
IpEndpointName remoteEndpoint;
struct timeval timeout;
while( !break_ ){
tempfds = masterfds;
struct timeval *timeoutPtr = 0;
if( !timerQueue_.empty() ){
double timeoutMs = timerQueue_.front().first - GetCurrentTimeMs();
if( timeoutMs < 0 )
timeoutMs = 0;
// 1000000 microseconds in a second
timeout.tv_sec = (long)(timeoutMs * .001);
timeout.tv_usec = (long)((timeoutMs - (timeout.tv_sec * 1000)) * 1000);
timeoutPtr = &timeout;
}
if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 && errno != EINTR ){
throw std::runtime_error("select failed\n");
}
if ( FD_ISSET( breakPipe_[0], &tempfds ) ){
// clear pending data from the asynchronous break pipe
char c;
read( breakPipe_[0], &c, 1 );
}
if( break_ )
break;
for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
i != socketListeners_.end(); ++i ){
if( FD_ISSET( i->second->impl_->Socket(), &tempfds ) ){
int size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE );
if( size > 0 ){
i->first->ProcessPacket( data, size, remoteEndpoint );
if( break_ )
break;
}
}
}
// execute any expired timers
currentTimeMs = GetCurrentTimeMs();
bool resort = false;
for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin();
i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){
i->second.listener->TimerExpired();
if( break_ )
break;
i->first += i->second.periodMs;
resort = true;
}
if( resort )
std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
}
delete [] data;
}
void Break()
{
break_ = true;
}
void AsynchronousBreak()
{
break_ = true;
// Send a termination message to the asynchronous break pipe, so select() will return
write( breakPipe_[1], "!", 1 );
}
};
SocketReceiveMultiplexer::SocketReceiveMultiplexer()
{
impl_ = new Implementation();
}
SocketReceiveMultiplexer::~SocketReceiveMultiplexer()
{
delete impl_;
}
void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener )
{
impl_->AttachSocketListener( socket, listener );
}
void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener )
{
impl_->DetachSocketListener( socket, listener );
}
void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
{
impl_->AttachPeriodicTimerListener( periodMilliseconds, listener );
}
void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
{
impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener );
}
void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener )
{
impl_->DetachPeriodicTimerListener( listener );
}
void SocketReceiveMultiplexer::Run()
{
impl_->Run();
}
void SocketReceiveMultiplexer::RunUntilSigInt()
{
assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */
multiplexerInstanceToAbortWithSigInt_ = this;
signal( SIGINT, InterruptSignalHandler );
impl_->Run();
signal( SIGINT, SIG_DFL );
multiplexerInstanceToAbortWithSigInt_ = 0;
}
void SocketReceiveMultiplexer::Break()
{
impl_->Break();
}
void SocketReceiveMultiplexer::AsynchronousBreak()
{
impl_->AsynchronousBreak();
}

View File

@@ -0,0 +1,88 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ip/NetworkingUtils.h"
#include <winsock2.h> // this must come first to prevent errors with MSVC7
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
static LONG initCount_ = 0;
static bool winsockInitialized_ = false;
NetworkInitializer::NetworkInitializer()
{
if( InterlockedIncrement( &initCount_ ) == 1 ){
// there is a race condition here if one thread tries to access
// the library while another is still initializing it.
// i can't think of an easy way to fix it so i'm telling you here
// incase you need to init the library from two threads at once.
// this is why the header file advises to instantiate one of these
// in main() so that the initialization happens globally
// initialize winsock
WSAData wsaData;
int nCode = WSAStartup(MAKEWORD(1, 1), &wsaData);
if( nCode != 0 ){
//std::cout << "WSAStartup() failed with error code " << nCode << "\n";
}else{
winsockInitialized_ = true;
}
}
}
NetworkInitializer::~NetworkInitializer()
{
if( InterlockedDecrement( &initCount_ ) == 0 ){
if( winsockInitialized_ ){
WSACleanup();
winsockInitialized_ = false;
}
}
}
unsigned long GetHostByName( const char *name )
{
NetworkInitializer networkInitializer;
unsigned long result = 0;
struct hostent *h = gethostbyname( name );
if( h ){
struct in_addr a;
memcpy( &a, h->h_addr_list[0], h->h_length );
result = ntohl(a.s_addr);
}
return result;
}

View File

@@ -0,0 +1,521 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ip/UdpSocket.h"
#include <winsock2.h> // this must come first to prevent errors with MSVC7
#include <windows.h>
#include <mmsystem.h> // for timeGetTime()
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <assert.h>
#include <signal.h>
#include "ip/NetworkingUtils.h"
#include "ip/PacketListener.h"
#include "ip/TimerListener.h"
typedef int socklen_t;
static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint )
{
memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr =
(endpoint.address == IpEndpointName::ANY_ADDRESS)
? INADDR_ANY
: htonl( endpoint.address );
sockAddr.sin_port =
(endpoint.port == IpEndpointName::ANY_PORT)
? (short)0
: htons( (short)endpoint.port );
}
static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr )
{
return IpEndpointName(
(sockAddr.sin_addr.s_addr == INADDR_ANY)
? IpEndpointName::ANY_ADDRESS
: ntohl( sockAddr.sin_addr.s_addr ),
(sockAddr.sin_port == 0)
? IpEndpointName::ANY_PORT
: ntohs( sockAddr.sin_port )
);
}
class UdpSocket::Implementation{
NetworkInitializer networkInitializer_;
bool isBound_;
bool isConnected_;
SOCKET socket_;
struct sockaddr_in connectedAddr_;
struct sockaddr_in sendToAddr_;
public:
Implementation()
: isBound_( false )
, isConnected_( false )
, socket_( INVALID_SOCKET )
{
if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == INVALID_SOCKET ){
throw std::runtime_error("unable to create udp socket\n");
}
memset( &sendToAddr_, 0, sizeof(sendToAddr_) );
sendToAddr_.sin_family = AF_INET;
}
~Implementation()
{
if (socket_ != INVALID_SOCKET) closesocket(socket_);
}
IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
{
assert( isBound_ );
// first connect the socket to the remote server
struct sockaddr_in connectSockAddr;
SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint );
if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) {
throw std::runtime_error("unable to connect udp socket\n");
}
// get the address
struct sockaddr_in sockAddr;
memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
socklen_t length = sizeof(sockAddr);
if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) {
throw std::runtime_error("unable to getsockname\n");
}
if( isConnected_ ){
// reconnect to the connected address
if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
throw std::runtime_error("unable to connect udp socket\n");
}
}else{
// unconnect from the remote address
struct sockaddr_in unconnectSockAddr;
SockaddrFromIpEndpointName( unconnectSockAddr, IpEndpointName() );
if( connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)) < 0
&& WSAGetLastError() != WSAEADDRNOTAVAIL ){
throw std::runtime_error("unable to un-connect udp socket\n");
}
}
return IpEndpointNameFromSockaddr( sockAddr );
}
void Connect( const IpEndpointName& remoteEndpoint )
{
SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint );
if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
throw std::runtime_error("unable to connect udp socket\n");
}
isConnected_ = true;
}
void Send( const char *data, int size )
{
assert( isConnected_ );
send( socket_, data, size, 0 );
}
void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size )
{
sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address );
sendToAddr_.sin_port = htons( (short)remoteEndpoint.port );
sendto( socket_, data, size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) );
}
void Bind( const IpEndpointName& localEndpoint )
{
struct sockaddr_in bindSockAddr;
SockaddrFromIpEndpointName( bindSockAddr, localEndpoint );
if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) {
throw std::runtime_error("unable to bind udp socket\n");
}
isBound_ = true;
}
bool IsBound() const { return isBound_; }
int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size )
{
assert( isBound_ );
struct sockaddr_in fromAddr;
socklen_t fromAddrLen = sizeof(fromAddr);
int result = recvfrom(socket_, data, size, 0,
(struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen);
if( result < 0 )
return 0;
remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr);
remoteEndpoint.port = ntohs(fromAddr.sin_port);
return result;
}
SOCKET& Socket() { return socket_; }
};
UdpSocket::UdpSocket()
{
impl_ = new Implementation();
}
UdpSocket::~UdpSocket()
{
delete impl_;
}
IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
{
return impl_->LocalEndpointFor( remoteEndpoint );
}
void UdpSocket::Connect( const IpEndpointName& remoteEndpoint )
{
impl_->Connect( remoteEndpoint );
}
void UdpSocket::Send( const char *data, int size )
{
impl_->Send( data, size );
}
void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size )
{
impl_->SendTo( remoteEndpoint, data, size );
}
void UdpSocket::Bind( const IpEndpointName& localEndpoint )
{
impl_->Bind( localEndpoint );
}
bool UdpSocket::IsBound() const
{
return impl_->IsBound();
}
int UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size )
{
return impl_->ReceiveFrom( remoteEndpoint, data, size );
}
struct AttachedTimerListener{
AttachedTimerListener( int id, int p, TimerListener *tl )
: initialDelayMs( id )
, periodMs( p )
, listener( tl ) {}
int initialDelayMs;
int periodMs;
TimerListener *listener;
};
static bool CompareScheduledTimerCalls(
const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs )
{
return lhs.first < rhs.first;
}
SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0;
extern "C" /*static*/ void InterruptSignalHandler( int );
/*static*/ void InterruptSignalHandler( int )
{
multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak();
signal( SIGINT, SIG_DFL );
}
class SocketReceiveMultiplexer::Implementation{
NetworkInitializer networkInitializer_;
std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_;
std::vector< AttachedTimerListener > timerListeners_;
volatile bool break_;
HANDLE breakEvent_;
double GetCurrentTimeMs() const
{
return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days
}
public:
Implementation()
{
breakEvent_ = CreateEvent( NULL, FALSE, FALSE, NULL );
}
~Implementation()
{
CloseHandle( breakEvent_ );
}
void AttachSocketListener( UdpSocket *socket, PacketListener *listener )
{
assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() );
// we don't check that the same socket has been added multiple times, even though this is an error
socketListeners_.push_back( std::make_pair( listener, socket ) );
}
void DetachSocketListener( UdpSocket *socket, PacketListener *listener )
{
std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i =
std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) );
assert( i != socketListeners_.end() );
socketListeners_.erase( i );
}
void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
{
timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) );
}
void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
{
timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) );
}
void DetachPeriodicTimerListener( TimerListener *listener )
{
std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
while( i != timerListeners_.end() ){
if( i->listener == listener )
break;
++i;
}
assert( i != timerListeners_.end() );
timerListeners_.erase( i );
}
void Run()
{
break_ = false;
// prepare the window events which we use to wake up on incoming data
// we use this instead of select() primarily to support the AsyncBreak()
// mechanism.
std::vector<HANDLE> events( socketListeners_.size() + 1, 0 );
int j=0;
for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
i != socketListeners_.end(); ++i, ++j ){
HANDLE event = CreateEvent( NULL, FALSE, FALSE, NULL );
WSAEventSelect( i->second->impl_->Socket(), event, FD_READ ); // note that this makes the socket non-blocking which is why we can safely call RecieveFrom() on all sockets below
events[j] = event;
}
events[ socketListeners_.size() ] = breakEvent_; // last event in the collection is the break event
// configure the timer queue
double currentTimeMs = GetCurrentTimeMs();
// expiry time ms, listener
std::vector< std::pair< double, AttachedTimerListener > > timerQueue_;
for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
i != timerListeners_.end(); ++i )
timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) );
std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
const int MAX_BUFFER_SIZE = 4098;
char *data = new char[ MAX_BUFFER_SIZE ];
IpEndpointName remoteEndpoint;
while( !break_ ){
double currentTimeMs = GetCurrentTimeMs();
DWORD waitTime = INFINITE;
if( !timerQueue_.empty() ){
waitTime = (DWORD)( timerQueue_.front().first >= currentTimeMs
? timerQueue_.front().first - currentTimeMs
: 0 );
}
DWORD waitResult = WaitForMultipleObjects( (DWORD)socketListeners_.size() + 1, &events[0], FALSE, waitTime );
if( break_ )
break;
if( waitResult != WAIT_TIMEOUT ){
for( int i = waitResult - WAIT_OBJECT_0; i < (int)socketListeners_.size(); ++i ){
int size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE );
if( size > 0 ){
socketListeners_[i].first->ProcessPacket( data, size, remoteEndpoint );
if( break_ )
break;
}
}
}
// execute any expired timers
currentTimeMs = GetCurrentTimeMs();
bool resort = false;
for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin();
i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){
i->second.listener->TimerExpired();
if( break_ )
break;
i->first += i->second.periodMs;
resort = true;
}
if( resort )
std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
}
delete [] data;
// free events
j = 0;
for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
i != socketListeners_.end(); ++i, ++j ){
WSAEventSelect( i->second->impl_->Socket(), events[j], 0 ); // remove association between socket and event
CloseHandle( events[j] );
unsigned long enableNonblocking = 0;
ioctlsocket( i->second->impl_->Socket(), FIONBIO, &enableNonblocking ); // make the socket blocking again
}
}
void Break()
{
break_ = true;
}
void AsynchronousBreak()
{
break_ = true;
SetEvent( breakEvent_ );
}
};
SocketReceiveMultiplexer::SocketReceiveMultiplexer()
{
impl_ = new Implementation();
}
SocketReceiveMultiplexer::~SocketReceiveMultiplexer()
{
delete impl_;
}
void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener )
{
impl_->AttachSocketListener( socket, listener );
}
void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener )
{
impl_->DetachSocketListener( socket, listener );
}
void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
{
impl_->AttachPeriodicTimerListener( periodMilliseconds, listener );
}
void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
{
impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener );
}
void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener )
{
impl_->DetachPeriodicTimerListener( listener );
}
void SocketReceiveMultiplexer::Run()
{
impl_->Run();
}
void SocketReceiveMultiplexer::RunUntilSigInt()
{
assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */
multiplexerInstanceToAbortWithSigInt_ = this;
signal( SIGINT, InterruptSignalHandler );
impl_->Run();
signal( SIGINT, SIG_DFL );
multiplexerInstanceToAbortWithSigInt_ = 0;
}
void SocketReceiveMultiplexer::Break()
{
impl_->Break();
}
void SocketReceiveMultiplexer::AsynchronousBreak()
{
impl_->AsynchronousBreak();
}

View File

@@ -1,80 +1,73 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions: subject to the following conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Any person wishing to distribute modifications to the Software is
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF requested to send the modifications to the original developer so that
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. they can be incorporated into the canonical version.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*/ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
/* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
The text above constitutes the entire oscpack license; however, WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
the oscpack developer(s) also make the following non-binding requests: */
#ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
Any person wishing to distribute modifications to the Software is #define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also #include <string.h>
requested that these non-binding requests be included whenever the #include <map>
above license is reproduced.
*/ #include "OscPacketListener.h"
#ifndef INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H
#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H
#include <cstring> namespace osc{
#include <map>
template< class T >
#include "OscPacketListener.h" class MessageMappingOscPacketListener : public OscPacketListener{
public:
typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&);
namespace osc{ protected:
void RegisterMessageFunction( const char *addressPattern, function_type f )
template< class T > {
class MessageMappingOscPacketListener : public OscPacketListener{ functions_.insert( std::make_pair( addressPattern, f ) );
public: }
typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&);
virtual void ProcessMessage( const osc::ReceivedMessage& m,
protected: const IpEndpointName& remoteEndpoint )
void RegisterMessageFunction( const char *addressPattern, function_type f ) {
{ typename function_map_type::iterator i = functions_.find( m.AddressPattern() );
functions_.insert( std::make_pair( addressPattern, f ) ); if( i != functions_.end() )
} (dynamic_cast<T*>(this)->*(i->second))( m, remoteEndpoint );
}
virtual void ProcessMessage( const osc::ReceivedMessage& m,
const IpEndpointName& remoteEndpoint ) private:
{ struct cstr_compare{
typename function_map_type::iterator i = functions_.find( m.AddressPattern() ); bool operator()( const char *lhs, const char *rhs ) const
if( i != functions_.end() ) { return strcmp( lhs, rhs ) < 0; }
(dynamic_cast<T*>(this)->*(i->second))( m, remoteEndpoint ); };
}
typedef std::map<const char*, function_type, cstr_compare> function_map_type;
private: function_map_type functions_;
struct cstr_compare{ };
bool operator()( const char *lhs, const char *rhs ) const
{ return std::strcmp( lhs, rhs ) < 0; } } // namespace osc
};
#endif /* INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H */
typedef std::map<const char*, function_type, cstr_compare> function_map_type;
function_map_type functions_;
};
} // namespace osc
#endif /* INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H */

View File

@@ -1,62 +1,54 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions: subject to the following conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Any person wishing to distribute modifications to the Software is
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF requested to send the modifications to the original developer so that
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. they can be incorporated into the canonical version.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*/ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
/* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
The text above constitutes the entire oscpack license; however, WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
the oscpack developer(s) also make the following non-binding requests: */
#ifndef INCLUDED_OSC_EXCEPTION_H
Any person wishing to distribute modifications to the Software is #define INCLUDED_OSC_EXCEPTION_H
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also #include <exception>
requested that these non-binding requests be included whenever the
above license is reproduced. namespace osc{
*/
#ifndef INCLUDED_OSCPACK_OSCEXCEPTION_H class Exception : public std::exception {
#define INCLUDED_OSCPACK_OSCEXCEPTION_H const char *what_;
#include <exception> public:
Exception() throw() {}
namespace osc{ Exception( const Exception& src ) throw()
: what_( src.what_ ) {}
class Exception : public std::exception { Exception( const char *w ) throw()
const char *what_; : what_( w ) {}
Exception& operator=( const Exception& src ) throw()
public: { what_ = src.what_; return *this; }
Exception() throw() {} virtual ~Exception() throw() {}
Exception( const Exception& src ) throw() virtual const char* what() const throw() { return what_; }
: std::exception( src ) };
, what_( src.what_ ) {}
Exception( const char *w ) throw() } // namespace osc
: what_( w ) {}
Exception& operator=( const Exception& src ) throw() #endif /* INCLUDED_OSC_EXCEPTION_H */
{ what_ = src.what_; return *this; }
virtual ~Exception() throw() {}
virtual const char* what() const throw() { return what_; }
};
} // namespace osc
#endif /* INCLUDED_OSCPACK_OSCEXCEPTION_H */

View File

@@ -0,0 +1,63 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef OSC_HOSTENDIANNESS_H
#define OSC_HOSTENDIANNESS_H
/*
Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined
If you know a way to enhance the detection below for Linux and/or MacOSX
please let me know! I've tried a few things which don't work.
*/
// you can define one of the above symbols from the command line
// then you don't have to edit this file.
#if defined(__WIN32__) || defined(WIN32)
// assume that __WIN32__ is only defined on little endian systems
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#else
#if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _LITTLE_ENDIAN)
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#else
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#endif
#endif // OSC_HOSTENDIANNESS_H

View File

@@ -1,154 +1,142 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions: subject to the following conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Any person wishing to distribute modifications to the Software is
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF requested to send the modifications to the original developer so that
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. they can be incorporated into the canonical version.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*/ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
/* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
The text above constitutes the entire oscpack license; however, WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
the oscpack developer(s) also make the following non-binding requests: */
#ifndef INCLUDED_OSCOUTBOUNDPACKET_H
Any person wishing to distribute modifications to the Software is #define INCLUDED_OSCOUTBOUNDPACKET_H
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also #include "OscTypes.h"
requested that these non-binding requests be included whenever the #include "OscException.h"
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H namespace osc{
#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H
class OutOfBufferMemoryException : public Exception{
#include <cstring> // size_t public:
OutOfBufferMemoryException( const char *w="out of buffer memory" )
#include "OscTypes.h" : Exception( w ) {}
#include "OscException.h" };
class BundleNotInProgressException : public Exception{
namespace osc{ public:
BundleNotInProgressException(
class OutOfBufferMemoryException : public Exception{ const char *w="call to EndBundle when bundle is not in progress" )
public: : Exception( w ) {}
OutOfBufferMemoryException( const char *w="out of buffer memory" ) };
: Exception( w ) {}
}; class MessageInProgressException : public Exception{
public:
class BundleNotInProgressException : public Exception{ MessageInProgressException(
public: const char *w="opening or closing bundle or message while message is in progress" )
BundleNotInProgressException( : Exception( w ) {}
const char *w="call to EndBundle when bundle is not in progress" ) };
: Exception( w ) {}
}; class MessageNotInProgressException : public Exception{
public:
class MessageInProgressException : public Exception{ MessageNotInProgressException(
public: const char *w="call to EndMessage when message is not in progress" )
MessageInProgressException( : Exception( w ) {}
const char *w="opening or closing bundle or message while message is in progress" ) };
: Exception( w ) {}
};
class OutboundPacketStream{
class MessageNotInProgressException : public Exception{ public:
public: OutboundPacketStream( char *buffer, unsigned long capacity );
MessageNotInProgressException( ~OutboundPacketStream();
const char *w="call to EndMessage when message is not in progress" )
: Exception( w ) {} void Clear();
};
unsigned int Capacity() const;
class OutboundPacketStream{ // invariant: size() is valid even while building a message.
public: unsigned int Size() const;
OutboundPacketStream( char *buffer, std::size_t capacity );
~OutboundPacketStream(); const char *Data() const;
void Clear(); // indicates that all messages have been closed with a matching EndMessage
// and all bundles have been closed with a matching EndBundle
std::size_t Capacity() const; bool IsReady() const;
// invariant: size() is valid even while building a message. bool IsMessageInProgress() const;
std::size_t Size() const; bool IsBundleInProgress() const;
const char *Data() const; OutboundPacketStream& operator<<( const BundleInitiator& rhs );
OutboundPacketStream& operator<<( const BundleTerminator& rhs );
// indicates that all messages have been closed with a matching EndMessage
// and all bundles have been closed with a matching EndBundle OutboundPacketStream& operator<<( const BeginMessage& rhs );
bool IsReady() const; OutboundPacketStream& operator<<( const MessageTerminator& rhs );
bool IsMessageInProgress() const; OutboundPacketStream& operator<<( bool rhs );
bool IsBundleInProgress() const; OutboundPacketStream& operator<<( const NilType& rhs );
OutboundPacketStream& operator<<( const InfinitumType& rhs );
OutboundPacketStream& operator<<( const BundleInitiator& rhs ); OutboundPacketStream& operator<<( int32 rhs );
OutboundPacketStream& operator<<( const BundleTerminator& rhs );
#ifndef x86_64
OutboundPacketStream& operator<<( const BeginMessage& rhs ); OutboundPacketStream& operator<<( int rhs )
OutboundPacketStream& operator<<( const MessageTerminator& rhs ); { *this << (int32)rhs; return *this; }
#endif
OutboundPacketStream& operator<<( bool rhs );
OutboundPacketStream& operator<<( const NilType& rhs ); OutboundPacketStream& operator<<( float rhs );
OutboundPacketStream& operator<<( const InfinitumType& rhs ); OutboundPacketStream& operator<<( char rhs );
OutboundPacketStream& operator<<( int32 rhs ); OutboundPacketStream& operator<<( const RgbaColor& rhs );
OutboundPacketStream& operator<<( const MidiMessage& rhs );
#if !(defined(__x86_64__) || defined(_M_X64)) OutboundPacketStream& operator<<( int64 rhs );
OutboundPacketStream& operator<<( int rhs ) OutboundPacketStream& operator<<( const TimeTag& rhs );
{ *this << (int32)rhs; return *this; } OutboundPacketStream& operator<<( double rhs );
#endif OutboundPacketStream& operator<<( const char* rhs );
OutboundPacketStream& operator<<( const Symbol& rhs );
OutboundPacketStream& operator<<( float rhs ); OutboundPacketStream& operator<<( const Blob& rhs );
OutboundPacketStream& operator<<( char rhs );
OutboundPacketStream& operator<<( const RgbaColor& rhs ); private:
OutboundPacketStream& operator<<( const MidiMessage& rhs );
OutboundPacketStream& operator<<( int64 rhs ); char *BeginElement( char *beginPtr );
OutboundPacketStream& operator<<( const TimeTag& rhs ); void EndElement( char *endPtr );
OutboundPacketStream& operator<<( double rhs );
OutboundPacketStream& operator<<( const char* rhs ); bool ElementSizeSlotRequired() const;
OutboundPacketStream& operator<<( const Symbol& rhs ); void CheckForAvailableBundleSpace();
OutboundPacketStream& operator<<( const Blob& rhs ); void CheckForAvailableMessageSpace( const char *addressPattern );
void CheckForAvailableArgumentSpace( long argumentLength );
OutboundPacketStream& operator<<( const ArrayInitiator& rhs );
OutboundPacketStream& operator<<( const ArrayTerminator& rhs ); char *data_;
char *end_;
private:
char *typeTagsCurrent_; // stored in reverse order
char *BeginElement( char *beginPtr ); char *messageCursor_;
void EndElement( char *endPtr ); char *argumentCurrent_;
bool ElementSizeSlotRequired() const; // elementSizePtr_ has two special values: 0 indicates that a bundle
void CheckForAvailableBundleSpace(); // isn't open, and elementSizePtr_==data_ indicates that a bundle is
void CheckForAvailableMessageSpace( const char *addressPattern ); // open but that it doesn't have a size slot (ie the outermost bundle)
void CheckForAvailableArgumentSpace( std::size_t argumentLength ); uint32 *elementSizePtr_;
char *data_; bool messageIsInProgress_;
char *end_; };
char *typeTagsCurrent_; // stored in reverse order } // namespace osc
char *messageCursor_;
char *argumentCurrent_; #endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */
// elementSizePtr_ has two special values: 0 indicates that a bundle
// isn't open, and elementSizePtr_==data_ indicates that a bundle is
// open but that it doesn't have a size slot (ie the outermost bundle)
uint32 *elementSizePtr_;
bool messageIsInProgress_;
};
} // namespace osc
#endif /* INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H */

View File

@@ -1,79 +1,72 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions: subject to the following conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Any person wishing to distribute modifications to the Software is
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF requested to send the modifications to the original developer so that
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. they can be incorporated into the canonical version.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*/ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
/* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
The text above constitutes the entire oscpack license; however, WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
the oscpack developer(s) also make the following non-binding requests: */
#ifndef INCLUDED_OSCPACKETLISTENER_H
Any person wishing to distribute modifications to the Software is #define INCLUDED_OSCPACKETLISTENER_H
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also #include "OscReceivedElements.h"
requested that these non-binding requests be included whenever the #include "../ip/PacketListener.h"
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCPACKETLISTENER_H namespace osc{
#define INCLUDED_OSCPACK_OSCPACKETLISTENER_H
class OscPacketListener : public PacketListener{
#include "OscReceivedElements.h" protected:
#include "../ip/PacketListener.h" virtual void ProcessBundle( const osc::ReceivedBundle& b,
const IpEndpointName& remoteEndpoint )
{
namespace osc{ // ignore bundle time tag for now
class OscPacketListener : public PacketListener{ for( ReceivedBundle::const_iterator i = b.ElementsBegin();
protected: i != b.ElementsEnd(); ++i ){
virtual void ProcessBundle( const osc::ReceivedBundle& b, if( i->IsBundle() )
const IpEndpointName& remoteEndpoint ) ProcessBundle( ReceivedBundle(*i), remoteEndpoint );
{ else
// ignore bundle time tag for now ProcessMessage( ReceivedMessage(*i), remoteEndpoint );
}
for( ReceivedBundle::const_iterator i = b.ElementsBegin(); }
i != b.ElementsEnd(); ++i ){
if( i->IsBundle() ) virtual void ProcessMessage( const osc::ReceivedMessage& m,
ProcessBundle( ReceivedBundle(*i), remoteEndpoint ); const IpEndpointName& remoteEndpoint ) = 0;
else
ProcessMessage( ReceivedMessage(*i), remoteEndpoint ); public:
} virtual void ProcessPacket( const char *data, int size,
} const IpEndpointName& remoteEndpoint )
{
virtual void ProcessMessage( const osc::ReceivedMessage& m, osc::ReceivedPacket p( data, size );
const IpEndpointName& remoteEndpoint ) = 0; if( p.IsBundle() )
ProcessBundle( ReceivedBundle(p), remoteEndpoint );
public: else
virtual void ProcessPacket( const char *data, int size, ProcessMessage( ReceivedMessage(p), remoteEndpoint );
const IpEndpointName& remoteEndpoint ) }
{ };
osc::ReceivedPacket p( data, size );
if( p.IsBundle() ) } // namespace osc
ProcessBundle( ReceivedBundle(p), remoteEndpoint );
else #endif /* INCLUDED_OSCPACKETLISTENER_H */
ProcessMessage( ReceivedMessage(p), remoteEndpoint );
}
};
} // namespace osc
#endif /* INCLUDED_OSCPACK_OSCPACKETLISTENER_H */

View File

@@ -1,261 +1,241 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions: subject to the following conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Any person wishing to distribute modifications to the Software is
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF requested to send the modifications to the original developer so that
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. they can be incorporated into the canonical version.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*/ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
/* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
The text above constitutes the entire oscpack license; however, WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
the oscpack developer(s) also make the following non-binding requests: */
#include "OscPrintReceivedElements.h"
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that #include <iostream>
they can be incorporated into the canonical version. It is also #include <cstring>
requested that these non-binding requests be included whenever the #include <iomanip>
above license is reproduced. #include <ctime>
*/
#include "OscPrintReceivedElements.h"
namespace osc{
#include <cstring>
#include <ctime>
#include <iostream> std::ostream& operator<<( std::ostream & os,
#include <iomanip> const ReceivedMessageArgument& arg )
{
#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug switch( arg.TypeTag() ){
namespace std { case TRUE_TYPE_TAG:
using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. os << "bool:true";
} break;
#endif
case FALSE_TYPE_TAG:
namespace osc{ os << "bool:false";
break;
std::ostream& operator<<( std::ostream & os, case NIL_TYPE_TAG:
const ReceivedMessageArgument& arg ) os << "(Nil)";
{ break;
switch( arg.TypeTag() ){
case TRUE_TYPE_TAG: case INFINITUM_TYPE_TAG:
os << "bool:true"; os << "(Infinitum)";
break; break;
case FALSE_TYPE_TAG: case INT32_TYPE_TAG:
os << "bool:false"; os << "int32:" << arg.AsInt32Unchecked();
break; break;
case NIL_TYPE_TAG: case FLOAT_TYPE_TAG:
os << "(Nil)"; os << "float32:" << arg.AsFloatUnchecked();
break; break;
case INFINITUM_TYPE_TAG: case CHAR_TYPE_TAG:
os << "(Infinitum)"; {
break; char s[2] = {0};
s[0] = arg.AsCharUnchecked();
case INT32_TYPE_TAG: os << "char:'" << s << "'";
os << "int32:" << arg.AsInt32Unchecked(); }
break; break;
case FLOAT_TYPE_TAG: case RGBA_COLOR_TYPE_TAG:
os << "float32:" << arg.AsFloatUnchecked(); {
break; uint32 color = arg.AsRgbaColorUnchecked();
case CHAR_TYPE_TAG: os << "RGBA:0x"
{ << std::hex << std::setfill('0')
char s[2] = {0}; << std::setw(2) << (int)((color>>24) & 0xFF)
s[0] = arg.AsCharUnchecked(); << std::setw(2) << (int)((color>>16) & 0xFF)
os << "char:'" << s << "'"; << std::setw(2) << (int)((color>>8) & 0xFF)
} << std::setw(2) << (int)(color & 0xFF)
break; << std::setfill(' ');
os.unsetf(std::ios::basefield);
case RGBA_COLOR_TYPE_TAG: }
{ break;
uint32 color = arg.AsRgbaColorUnchecked();
case MIDI_MESSAGE_TYPE_TAG:
os << "RGBA:0x" {
<< std::hex << std::setfill('0') uint32 m = arg.AsMidiMessageUnchecked();
<< std::setw(2) << (int)((color>>24) & 0xFF) os << "midi (port, status, data1, data2):<<"
<< std::setw(2) << (int)((color>>16) & 0xFF) << std::hex << std::setfill('0')
<< std::setw(2) << (int)((color>>8) & 0xFF) << "0x" << std::setw(2) << (int)((m>>24) & 0xFF)
<< std::setw(2) << (int)(color & 0xFF) << " 0x" << std::setw(2) << (int)((m>>16) & 0xFF)
<< std::setfill(' '); << " 0x" << std::setw(2) << (int)((m>>8) & 0xFF)
os.unsetf(std::ios::basefield); << " 0x" << std::setw(2) << (int)(m & 0xFF)
} << std::setfill(' ') << ">>";
break; os.unsetf(std::ios::basefield);
}
case MIDI_MESSAGE_TYPE_TAG: break;
{
uint32 m = arg.AsMidiMessageUnchecked(); case INT64_TYPE_TAG:
os << "midi (port, status, data1, data2):<<" os << "int64:" << arg.AsInt64Unchecked();
<< std::hex << std::setfill('0') break;
<< "0x" << std::setw(2) << (int)((m>>24) & 0xFF)
<< " 0x" << std::setw(2) << (int)((m>>16) & 0xFF) case TIME_TAG_TYPE_TAG:
<< " 0x" << std::setw(2) << (int)((m>>8) & 0xFF) {
<< " 0x" << std::setw(2) << (int)(m & 0xFF) os << "OSC-timetag:" << arg.AsTimeTagUnchecked();
<< std::setfill(' ') << ">>";
os.unsetf(std::ios::basefield); std::time_t t =
} (unsigned long)( arg.AsTimeTagUnchecked() >> 32 );
break;
// strip trailing newline from string returned by ctime
case INT64_TYPE_TAG: const char *timeString = std::ctime( &t );
os << "int64:" << arg.AsInt64Unchecked(); size_t len = strlen( timeString );
break; char *s = new char[ len + 1 ];
strcpy( s, timeString );
case TIME_TAG_TYPE_TAG: if( len )
{ s[ len - 1 ] = '\0';
os << "OSC-timetag:" << arg.AsTimeTagUnchecked() << " ";
os << " " << s;
std::time_t t = }
(unsigned long)( arg.AsTimeTagUnchecked() >> 32 ); break;
const char *timeString = std::ctime( &t ); case DOUBLE_TYPE_TAG:
size_t len = std::strlen( timeString ); os << "double:" << arg.AsDoubleUnchecked();
break;
// -1 to omit trailing newline from string returned by ctime()
if( len > 1 ) case STRING_TYPE_TAG:
os.write( timeString, len - 1 ); os << "OSC-string:`" << arg.AsStringUnchecked() << "'";
} break;
break;
case SYMBOL_TYPE_TAG:
case DOUBLE_TYPE_TAG: os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'";
os << "double:" << arg.AsDoubleUnchecked(); break;
break;
case BLOB_TYPE_TAG:
case STRING_TYPE_TAG: {
os << "OSC-string:`" << arg.AsStringUnchecked() << "'"; unsigned long size;
break; const void *data;
arg.AsBlobUnchecked( data, size );
case SYMBOL_TYPE_TAG: os << "OSC-blob:<<" << std::hex << std::setfill('0');
os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'"; unsigned char *p = (unsigned char*)data;
break; for( unsigned long i = 0; i < size; ++i ){
os << "0x" << std::setw(2) << int(p[i]);
case BLOB_TYPE_TAG: if( i != size-1 )
{ os << ' ';
const void *data; }
osc_bundle_element_size_t size; os.unsetf(std::ios::basefield);
arg.AsBlobUnchecked( data, size ); os << ">>" << std::setfill(' ');
os << "OSC-blob:<<" << std::hex << std::setfill('0'); }
unsigned char *p = (unsigned char*)data; break;
for( osc_bundle_element_size_t i = 0; i < size; ++i ){
os << "0x" << std::setw(2) << int(p[i]); default:
if( i != size-1 ) os << "unknown";
os << ' '; }
}
os.unsetf(std::ios::basefield); return os;
os << ">>" << std::setfill(' '); }
}
break;
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )
case ARRAY_BEGIN_TYPE_TAG: {
os << "[";
break; os << "[" << m.AddressPattern();
bool first = true;
case ARRAY_END_TYPE_TAG:
os << "]"; for( ReceivedMessage::const_iterator i = m.ArgumentsBegin();
break; i != m.ArgumentsEnd(); ++i ){
if( first ){
default: os << " ";
os << "unknown"; first = false;
} }else{
os << ", ";
return os; }
}
os << *i;
}
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )
{ os << "]";
os << "[";
if( m.AddressPatternIsUInt32() ) return os;
os << m.AddressPatternAsUInt32(); }
else
os << m.AddressPattern();
std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b )
bool first = true; {
for( ReceivedMessage::const_iterator i = m.ArgumentsBegin(); static int indent = 0;
i != m.ArgumentsEnd(); ++i ){
if( first ){ for( int j=0; j < indent; ++j )
os << " "; os << " ";
first = false; os << "{ ( ";
}else{ if( b.TimeTag() == 1 )
os << ", "; os << "immediate";
} else
os << b.TimeTag();
os << *i; os << " )\n";
}
++indent;
os << "]";
for( ReceivedBundle::const_iterator i = b.ElementsBegin();
return os; i != b.ElementsEnd(); ++i ){
} if( i->IsBundle() ){
ReceivedBundle b(*i);
os << b << "\n";
std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ) }else{
{ ReceivedMessage m(*i);
static int indent = 0; for( int j=0; j < indent; ++j )
os << " ";
for( int j=0; j < indent; ++j ) os << m << "\n";
os << " "; }
os << "{ ( "; }
if( b.TimeTag() == 1 )
os << "immediate"; --indent;
else
os << b.TimeTag(); for( int j=0; j < indent; ++j )
os << " )\n"; os << " ";
os << "}";
++indent;
return os;
for( ReceivedBundle::const_iterator i = b.ElementsBegin(); }
i != b.ElementsEnd(); ++i ){
if( i->IsBundle() ){
ReceivedBundle b(*i); std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p )
os << b << "\n"; {
}else{ if( p.IsBundle() ){
ReceivedMessage m(*i); ReceivedBundle b(p);
for( int j=0; j < indent; ++j ) os << b << "\n";
os << " "; }else{
os << m << "\n"; ReceivedMessage m(p);
} os << m << "\n";
} }
--indent; return os;
}
for( int j=0; j < indent; ++j )
os << " "; } // namespace osc
os << "}";
return os;
}
std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p )
{
if( p.IsBundle() ){
ReceivedBundle b(p);
os << b << "\n";
}else{
ReceivedMessage m(p);
os << m << "\n";
}
return os;
}
} // namespace osc

View File

@@ -1,54 +1,49 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions: subject to the following conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Any person wishing to distribute modifications to the Software is
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF requested to send the modifications to the original developer so that
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. they can be incorporated into the canonical version.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*/ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
/* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
The text above constitutes the entire oscpack license; however, WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
the oscpack developer(s) also make the following non-binding requests: */
#ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
Any person wishing to distribute modifications to the Software is #define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also #include <iosfwd>
requested that these non-binding requests be included whenever the
above license is reproduced. #ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
*/ #include "OscReceivedElements.h"
#ifndef INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H #endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
#define INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H
#include <iosfwd> namespace osc{
#include "OscReceivedElements.h" std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p );
std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg );
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m );
namespace osc{ std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b );
std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p ); } // namespace osc
std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg );
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ); #endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */
std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b );
} // namespace osc
#endif /* INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H */

View File

@@ -0,0 +1,722 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "OscReceivedElements.h"
#include <cassert>
#include "OscHostEndianness.h"
namespace osc{
// return the first 4 byte boundary after the end of a str4
// be careful about calling this version if you don't know whether
// the string is terminated correctly.
static inline const char* FindStr4End( const char *p )
{
if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
return p + 4;
p += 3;
while( *p )
p += 4;
return p + 1;
}
// return the first 4 byte boundary after the end of a str4
// returns 0 if p == end or if the string is unterminated
static inline const char* FindStr4End( const char *p, const char *end )
{
if( p >= end )
return 0;
if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
return p + 4;
p += 3;
end -= 1;
while( p < end && *p )
p += 4;
if( *p )
return 0;
else
return p + 1;
}
static inline unsigned long RoundUp4( unsigned long x )
{
unsigned long remainder = x & 0x3UL;
if( remainder )
return x + (4 - remainder);
else
return x;
}
static inline int32 ToInt32( const char *p )
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::int32 i;
char c[4];
} u;
u.c[0] = p[3];
u.c[1] = p[2];
u.c[2] = p[1];
u.c[3] = p[0];
return u.i;
#else
return *(int32*)p;
#endif
}
static inline uint32 ToUInt32( const char *p )
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::uint32 i;
char c[4];
} u;
u.c[0] = p[3];
u.c[1] = p[2];
u.c[2] = p[1];
u.c[3] = p[0];
return u.i;
#else
return *(uint32*)p;
#endif
}
int64 ToInt64( const char *p )
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::int64 i;
char c[4];
} u;
u.c[0] = p[7];
u.c[1] = p[6];
u.c[2] = p[5];
u.c[3] = p[4];
u.c[4] = p[3];
u.c[5] = p[2];
u.c[6] = p[1];
u.c[7] = p[0];
return u.i;
#else
return *(int64*)p;
#endif
}
uint64 ToUInt64( const char *p )
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::uint64 i;
char c[4];
} u;
u.c[0] = p[7];
u.c[1] = p[6];
u.c[2] = p[5];
u.c[3] = p[4];
u.c[4] = p[3];
u.c[5] = p[2];
u.c[6] = p[1];
u.c[7] = p[0];
return u.i;
#else
return *(uint64*)p;
#endif
}
//------------------------------------------------------------------------------
bool ReceivedPacket::IsBundle() const
{
return (Size() > 0 && Contents()[0] == '#');
}
//------------------------------------------------------------------------------
bool ReceivedBundleElement::IsBundle() const
{
return (Size() > 0 && Contents()[0] == '#');
}
int32 ReceivedBundleElement::Size() const
{
return ToUInt32( size_ );
}
//------------------------------------------------------------------------------
bool ReceivedMessageArgument::AsBool() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == TRUE_TYPE_TAG )
return true;
else if( *typeTag_ == FALSE_TYPE_TAG )
return false;
else
throw WrongArgumentTypeException();
}
bool ReceivedMessageArgument::AsBoolUnchecked() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == TRUE_TYPE_TAG )
return true;
else
return false;
}
int32 ReceivedMessageArgument::AsInt32() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == INT32_TYPE_TAG )
return AsInt32Unchecked();
else
throw WrongArgumentTypeException();
}
int32 ReceivedMessageArgument::AsInt32Unchecked() const
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::int32 i;
char c[4];
} u;
u.c[0] = argument_[3];
u.c[1] = argument_[2];
u.c[2] = argument_[1];
u.c[3] = argument_[0];
return u.i;
#else
return *(int32*)argument_;
#endif
}
float ReceivedMessageArgument::AsFloat() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == FLOAT_TYPE_TAG )
return AsFloatUnchecked();
else
throw WrongArgumentTypeException();
}
float ReceivedMessageArgument::AsFloatUnchecked() const
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
float f;
char c[4];
} u;
u.c[0] = argument_[3];
u.c[1] = argument_[2];
u.c[2] = argument_[1];
u.c[3] = argument_[0];
return u.f;
#else
return *(float*)argument_;
#endif
}
char ReceivedMessageArgument::AsChar() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == CHAR_TYPE_TAG )
return AsCharUnchecked();
else
throw WrongArgumentTypeException();
}
char ReceivedMessageArgument::AsCharUnchecked() const
{
return (char)ToInt32( argument_ );
}
uint32 ReceivedMessageArgument::AsRgbaColor() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == RGBA_COLOR_TYPE_TAG )
return AsRgbaColorUnchecked();
else
throw WrongArgumentTypeException();
}
uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
{
return ToUInt32( argument_ );
}
uint32 ReceivedMessageArgument::AsMidiMessage() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG )
return AsMidiMessageUnchecked();
else
throw WrongArgumentTypeException();
}
uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
{
return ToUInt32( argument_ );
}
int64 ReceivedMessageArgument::AsInt64() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == INT64_TYPE_TAG )
return AsInt64Unchecked();
else
throw WrongArgumentTypeException();
}
int64 ReceivedMessageArgument::AsInt64Unchecked() const
{
return ToInt64( argument_ );
}
uint64 ReceivedMessageArgument::AsTimeTag() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == TIME_TAG_TYPE_TAG )
return AsTimeTagUnchecked();
else
throw WrongArgumentTypeException();
}
uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
{
return ToUInt64( argument_ );
}
double ReceivedMessageArgument::AsDouble() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == DOUBLE_TYPE_TAG )
return AsDoubleUnchecked();
else
throw WrongArgumentTypeException();
}
double ReceivedMessageArgument::AsDoubleUnchecked() const
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
double d;
char c[8];
} u;
u.c[0] = argument_[7];
u.c[1] = argument_[6];
u.c[2] = argument_[5];
u.c[3] = argument_[4];
u.c[4] = argument_[3];
u.c[5] = argument_[2];
u.c[6] = argument_[1];
u.c[7] = argument_[0];
return u.d;
#else
return *(double*)argument_;
#endif
}
const char* ReceivedMessageArgument::AsString() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == STRING_TYPE_TAG )
return argument_;
else
throw WrongArgumentTypeException();
}
const char* ReceivedMessageArgument::AsSymbol() const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == SYMBOL_TYPE_TAG )
return argument_;
else
throw WrongArgumentTypeException();
}
void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const
{
if( !typeTag_ )
throw MissingArgumentException();
else if( *typeTag_ == BLOB_TYPE_TAG )
AsBlobUnchecked( data, size );
else
throw WrongArgumentTypeException();
}
void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const
{
size = ToUInt32( argument_ );
data = (void*)(argument_+4);
}
//------------------------------------------------------------------------------
void ReceivedMessageArgumentIterator::Advance()
{
if( !value_.typeTag_ )
return;
switch( *value_.typeTag_++ ){
case '\0':
// don't advance past end
--value_.typeTag_;
break;
case TRUE_TYPE_TAG:
case FALSE_TYPE_TAG:
case NIL_TYPE_TAG:
case INFINITUM_TYPE_TAG:
// zero length
break;
case INT32_TYPE_TAG:
case FLOAT_TYPE_TAG:
case CHAR_TYPE_TAG:
case RGBA_COLOR_TYPE_TAG:
case MIDI_MESSAGE_TYPE_TAG:
value_.argument_ += 4;
break;
case INT64_TYPE_TAG:
case TIME_TAG_TYPE_TAG:
case DOUBLE_TYPE_TAG:
value_.argument_ += 8;
break;
case STRING_TYPE_TAG:
case SYMBOL_TYPE_TAG:
// we use the unsafe function FindStr4End(char*) here because all of
// the arguments have already been validated in
// ReceivedMessage::Init() below.
value_.argument_ = FindStr4End( value_.argument_ );
break;
case BLOB_TYPE_TAG:
{
uint32 blobSize = ToUInt32( value_.argument_ );
value_.argument_ = value_.argument_ + 4 + RoundUp4( blobSize );
}
break;
default: // unknown type tag
// don't advance
--value_.typeTag_;
break;
// not handled:
// [ Indicates the beginning of an array. The tags following are for
// data in the Array until a close brace tag is reached.
// ] Indicates the end of an array.
}
}
//------------------------------------------------------------------------------
ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )
: addressPattern_( packet.Contents() )
{
Init( packet.Contents(), packet.Size() );
}
ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
: addressPattern_( bundleElement.Contents() )
{
Init( bundleElement.Contents(), bundleElement.Size() );
}
bool ReceivedMessage::AddressPatternIsUInt32() const
{
return (addressPattern_[0] == '\0');
}
uint32 ReceivedMessage::AddressPatternAsUInt32() const
{
return ToUInt32( addressPattern_ );
}
void ReceivedMessage::Init( const char *message, unsigned long size )
{
if( size == 0 )
throw MalformedMessageException( "zero length messages not permitted" );
if( (size & 0x03L) != 0 )
throw MalformedMessageException( "message size must be multiple of four" );
const char *end = message + size;
typeTagsBegin_ = FindStr4End( addressPattern_, end );
if( typeTagsBegin_ == 0 ){
// address pattern was not terminated before end
throw MalformedMessageException( "unterminated address pattern" );
}
if( typeTagsBegin_ == end ){
// message consists of only the address pattern - no arguments or type tags.
typeTagsBegin_ = 0;
typeTagsEnd_ = 0;
arguments_ = 0;
}else{
if( *typeTagsBegin_ != ',' )
throw MalformedMessageException( "type tags not present" );
if( *(typeTagsBegin_ + 1) == '\0' ){
// zero length type tags
typeTagsBegin_ = 0;
typeTagsEnd_ = 0;
arguments_ = 0;
}else{
// check that all arguments are present and well formed
arguments_ = FindStr4End( typeTagsBegin_, end );
if( arguments_ == 0 ){
throw MalformedMessageException( "type tags were not terminated before end of message" );
}
++typeTagsBegin_; // advance past initial ','
const char *typeTag = typeTagsBegin_;
const char *argument = arguments_;
do{
switch( *typeTag ){
case TRUE_TYPE_TAG:
case FALSE_TYPE_TAG:
case NIL_TYPE_TAG:
case INFINITUM_TYPE_TAG:
// zero length
break;
case INT32_TYPE_TAG:
case FLOAT_TYPE_TAG:
case CHAR_TYPE_TAG:
case RGBA_COLOR_TYPE_TAG:
case MIDI_MESSAGE_TYPE_TAG:
if( argument == end )
throw MalformedMessageException( "arguments exceed message size" );
argument += 4;
if( argument > end )
throw MalformedMessageException( "arguments exceed message size" );
break;
case INT64_TYPE_TAG:
case TIME_TAG_TYPE_TAG:
case DOUBLE_TYPE_TAG:
if( argument == end )
throw MalformedMessageException( "arguments exceed message size" );
argument += 8;
if( argument > end )
throw MalformedMessageException( "arguments exceed message size" );
break;
case STRING_TYPE_TAG:
case SYMBOL_TYPE_TAG:
if( argument == end )
throw MalformedMessageException( "arguments exceed message size" );
argument = FindStr4End( argument, end );
if( argument == 0 )
throw MalformedMessageException( "unterminated string argument" );
break;
case BLOB_TYPE_TAG:
{
if( argument + 4 > end )
MalformedMessageException( "arguments exceed message size" );
uint32 blobSize = ToUInt32( argument );
argument = argument + 4 + RoundUp4( blobSize );
if( argument > end )
MalformedMessageException( "arguments exceed message size" );
}
break;
default:
throw MalformedMessageException( "unknown type tag" );
// not handled:
// [ Indicates the beginning of an array. The tags following are for
// data in the Array until a close brace tag is reached.
// ] Indicates the end of an array.
}
}while( *++typeTag != '\0' );
typeTagsEnd_ = typeTag;
}
}
}
//------------------------------------------------------------------------------
ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )
: elementCount_( 0 )
{
Init( packet.Contents(), packet.Size() );
}
ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
: elementCount_( 0 )
{
Init( bundleElement.Contents(), bundleElement.Size() );
}
void ReceivedBundle::Init( const char *bundle, unsigned long size )
{
if( size < 16 )
throw MalformedBundleException( "packet too short for bundle" );
if( (size & 0x03L) != 0 )
throw MalformedBundleException( "bundle size must be multiple of four" );
if( bundle[0] != '#'
|| bundle[1] != 'b'
|| bundle[2] != 'u'
|| bundle[3] != 'n'
|| bundle[4] != 'd'
|| bundle[5] != 'l'
|| bundle[6] != 'e'
|| bundle[7] != '\0' )
throw MalformedBundleException( "bad bundle address pattern" );
end_ = bundle + size;
timeTag_ = bundle + 8;
const char *p = timeTag_ + 8;
while( p < end_ ){
if( p + 4 > end_ )
throw MalformedBundleException( "packet too short for elementSize" );
uint32 elementSize = ToUInt32( p );
if( (elementSize & 0x03L) != 0 )
throw MalformedBundleException( "bundle element size must be multiple of four" );
p += 4 + elementSize;
if( p > end_ )
throw MalformedBundleException( "packet too short for bundle element" );
++elementCount_;
}
if( p != end_ )
throw MalformedBundleException( "bundle contents " );
}
uint64 ReceivedBundle::TimeTag() const
{
return ToUInt64( timeTag_ );
}
} // namespace osc

View File

@@ -1,52 +1,40 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions: subject to the following conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Any person wishing to distribute modifications to the Software is
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF requested to send the modifications to the original developer so that
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. they can be incorporated into the canonical version.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*/ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
/* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
The text above constitutes the entire oscpack license; however, WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
the oscpack developer(s) also make the following non-binding requests: */
#include "OscTypes.h"
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that namespace osc{
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the BundleInitiator BeginBundleImmediate(1);
above license is reproduced. BundleTerminator EndBundle;
*/ MessageTerminator EndMessage;
#include "OscTypes.h" NilType Nil;
InfinitumType Infinitum;
namespace osc{
} // namespace osc
BundleInitiator BeginBundleImmediate(1);
BundleTerminator EndBundle;
MessageTerminator EndMessage;
NilType OscNil;
#ifndef _OBJC_OBJC_H_
NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead
#endif
InfinitumType Infinitum;
ArrayInitiator BeginArray;
ArrayTerminator EndArray;
} // namespace osc

View File

@@ -1,240 +1,178 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions: subject to the following conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Any person wishing to distribute modifications to the Software is
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF requested to send the modifications to the original developer so that
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. they can be incorporated into the canonical version.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*/ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
/* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
The text above constitutes the entire oscpack license; however, WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
the oscpack developer(s) also make the following non-binding requests: */
#ifndef INCLUDED_OSCTYPES_H
Any person wishing to distribute modifications to the Software is #define INCLUDED_OSCTYPES_H
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the namespace osc{
above license is reproduced.
*/ // basic types
#ifndef INCLUDED_OSCPACK_OSCTYPES_H
#define INCLUDED_OSCPACK_OSCTYPES_H #if defined(__BORLANDC__) || defined(_MSC_VER)
typedef __int64 int64;
namespace osc{ typedef unsigned __int64 uint64;
// basic types #else
#if defined(__BORLANDC__) || defined(_MSC_VER) typedef long long int64;
typedef unsigned long long uint64;
typedef __int64 int64;
typedef unsigned __int64 uint64; #endif
#elif defined(__x86_64__) || defined(_M_X64)
typedef long int64; #ifdef x86_64
typedef unsigned long uint64;
typedef signed int int32;
#else typedef unsigned int uint32;
typedef long long int64; #else
typedef unsigned long long uint64;
typedef signed long int32;
#endif typedef unsigned long uint32;
#endif
#if defined(__x86_64__) || defined(_M_X64)
typedef signed int int32; enum TypeTagValues {
typedef unsigned int uint32; TRUE_TYPE_TAG = 'T',
FALSE_TYPE_TAG = 'F',
#else NIL_TYPE_TAG = 'N',
INFINITUM_TYPE_TAG = 'I',
typedef signed long int32; INT32_TYPE_TAG = 'i',
typedef unsigned long uint32; FLOAT_TYPE_TAG = 'f',
CHAR_TYPE_TAG = 'c',
#endif RGBA_COLOR_TYPE_TAG = 'r',
MIDI_MESSAGE_TYPE_TAG = 'm',
INT64_TYPE_TAG = 'h',
enum ValueTypeSizes{ TIME_TAG_TYPE_TAG = 't',
OSC_SIZEOF_INT32 = 4, DOUBLE_TYPE_TAG = 'd',
OSC_SIZEOF_UINT32 = 4, STRING_TYPE_TAG = 's',
OSC_SIZEOF_INT64 = 8, SYMBOL_TYPE_TAG = 'S',
OSC_SIZEOF_UINT64 = 8, BLOB_TYPE_TAG = 'b'
}; };
// osc_bundle_element_size_t is used for the size of bundle elements and blobs
// the OSC spec specifies these as int32 (signed) but we ensure that they // i/o manipulators used for streaming interfaces
// are always positive since negative field sizes make no sense.
struct BundleInitiator{
typedef int32 osc_bundle_element_size_t; explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {}
uint64 timeTag;
enum { };
OSC_INT32_MAX = 0x7FFFFFFF,
extern BundleInitiator BeginBundleImmediate;
// Element sizes are specified to be int32, and are always rounded up to nearest
// multiple of 4. Therefore their values can't be greater than 0x7FFFFFFC. inline BundleInitiator BeginBundle( uint64 timeTag=1 )
OSC_BUNDLE_ELEMENT_SIZE_MAX = 0x7FFFFFFC {
}; return BundleInitiator(timeTag);
}
inline bool IsValidElementSizeValue( osc_bundle_element_size_t x )
{ struct BundleTerminator{
// sizes may not be negative or exceed OSC_BUNDLE_ELEMENT_SIZE_MAX };
return x >= 0 && x <= OSC_BUNDLE_ELEMENT_SIZE_MAX;
} extern BundleTerminator EndBundle;
struct BeginMessage{
inline bool IsMultipleOf4( osc_bundle_element_size_t x ) explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {}
{ const char *addressPattern;
return (x & ((osc_bundle_element_size_t)0x03)) == 0; };
}
struct MessageTerminator{
};
enum TypeTagValues {
TRUE_TYPE_TAG = 'T', extern MessageTerminator EndMessage;
FALSE_TYPE_TAG = 'F',
NIL_TYPE_TAG = 'N',
INFINITUM_TYPE_TAG = 'I', // osc specific types. they are defined as structs so they can be used
INT32_TYPE_TAG = 'i', // as separately identifiable types with the streaming operators.
FLOAT_TYPE_TAG = 'f',
CHAR_TYPE_TAG = 'c', struct NilType{
RGBA_COLOR_TYPE_TAG = 'r', };
MIDI_MESSAGE_TYPE_TAG = 'm',
INT64_TYPE_TAG = 'h', extern NilType Nil;
TIME_TAG_TYPE_TAG = 't',
DOUBLE_TYPE_TAG = 'd',
STRING_TYPE_TAG = 's', struct InfinitumType{
SYMBOL_TYPE_TAG = 'S', };
BLOB_TYPE_TAG = 'b',
ARRAY_BEGIN_TYPE_TAG = '[', extern InfinitumType Infinitum;
ARRAY_END_TYPE_TAG = ']'
}; struct RgbaColor{
RgbaColor() {}
explicit RgbaColor( uint32 value_ ) : value( value_ ) {}
uint32 value;
// i/o manipulators used for streaming interfaces
operator uint32() const { return value; }
struct BundleInitiator{ };
explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {}
uint64 timeTag;
}; struct MidiMessage{
MidiMessage() {}
extern BundleInitiator BeginBundleImmediate; explicit MidiMessage( uint32 value_ ) : value( value_ ) {}
uint32 value;
inline BundleInitiator BeginBundle( uint64 timeTag=1 )
{ operator uint32() const { return value; }
return BundleInitiator(timeTag); };
}
struct TimeTag{
struct BundleTerminator{ TimeTag() {}
}; explicit TimeTag( uint64 value_ ) : value( value_ ) {}
uint64 value;
extern BundleTerminator EndBundle;
operator uint64() const { return value; }
struct BeginMessage{ };
explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {}
const char *addressPattern;
}; struct Symbol{
Symbol() {}
struct MessageTerminator{ explicit Symbol( const char* value_ ) : value( value_ ) {}
}; const char* value;
extern MessageTerminator EndMessage; operator const char *() const { return value; }
};
// osc specific types. they are defined as structs so they can be used
// as separately identifiable types with the streaming operators. struct Blob{
Blob() {}
struct NilType{ explicit Blob( const void* data_, unsigned long size_ )
}; : data( data_ ), size( size_ ) {}
const void* data;
extern NilType OscNil; unsigned long size;
};
#ifndef _OBJC_OBJC_H_
extern NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead } // namespace osc
#endif
struct InfinitumType{ #endif /* INCLUDED_OSCTYPES_H */
};
extern InfinitumType Infinitum;
struct RgbaColor{
RgbaColor() {}
explicit RgbaColor( uint32 value_ ) : value( value_ ) {}
uint32 value;
operator uint32() const { return value; }
};
struct MidiMessage{
MidiMessage() {}
explicit MidiMessage( uint32 value_ ) : value( value_ ) {}
uint32 value;
operator uint32() const { return value; }
};
struct TimeTag{
TimeTag() {}
explicit TimeTag( uint64 value_ ) : value( value_ ) {}
uint64 value;
operator uint64() const { return value; }
};
struct Symbol{
Symbol() {}
explicit Symbol( const char* value_ ) : value( value_ ) {}
const char* value;
operator const char *() const { return value; }
};
struct Blob{
Blob() {}
explicit Blob( const void* data_, osc_bundle_element_size_t size_ )
: data( data_ ), size( size_ ) {}
const void* data;
osc_bundle_element_size_t size;
};
struct ArrayInitiator{
};
extern ArrayInitiator BeginArray;
struct ArrayTerminator{
};
extern ArrayTerminator EndArray;
} // namespace osc
#endif /* INCLUDED_OSCPACK_OSCTYPES_H */