mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-05 23:40:02 +01:00
Complete integration of original OSCPack lib
This commit is contained in:
@@ -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}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
|
|
||||||
81
ext/OSCPack/ip/IpEndpointName.cpp
Normal file
81
ext/OSCPack/ip/IpEndpointName.cpp
Normal 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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
ext/OSCPack/ip/IpEndpointName.h
Normal file
74
ext/OSCPack/ip/IpEndpointName.h
Normal 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 */
|
||||||
49
ext/OSCPack/ip/NetworkingUtils.h
Normal file
49
ext/OSCPack/ip/NetworkingUtils.h
Normal 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 */
|
||||||
43
ext/OSCPack/ip/PacketListener.h
Normal file
43
ext/OSCPack/ip/PacketListener.h
Normal 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 */
|
||||||
40
ext/OSCPack/ip/TimerListener.h
Normal file
40
ext/OSCPack/ip/TimerListener.h
Normal 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
158
ext/OSCPack/ip/UdpSocket.h
Normal 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 */
|
||||||
57
ext/OSCPack/ip/posix/NetworkingUtils.cpp
Normal file
57
ext/OSCPack/ip/posix/NetworkingUtils.cpp
Normal 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;
|
||||||
|
}
|
||||||
546
ext/OSCPack/ip/posix/UdpSocket.cpp
Normal file
546
ext/OSCPack/ip/posix/UdpSocket.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
88
ext/OSCPack/ip/win32/NetworkingUtils.cpp
Normal file
88
ext/OSCPack/ip/win32/NetworkingUtils.cpp
Normal 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;
|
||||||
|
}
|
||||||
521
ext/OSCPack/ip/win32/UdpSocket.cpp
Normal file
521
ext/OSCPack/ip/win32/UdpSocket.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
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
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
@@ -23,21 +27,10 @@
|
|||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
|
||||||
|
#define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
|
||||||
|
|
||||||
/*
|
#include <string.h>
|
||||||
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_MESSAGEMAPPINGOSCPACKETLISTENER_H
|
|
||||||
#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "OscPacketListener.h"
|
#include "OscPacketListener.h"
|
||||||
@@ -68,7 +61,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
struct cstr_compare{
|
struct cstr_compare{
|
||||||
bool operator()( const char *lhs, const char *rhs ) const
|
bool operator()( const char *lhs, const char *rhs ) const
|
||||||
{ return std::strcmp( lhs, rhs ) < 0; }
|
{ return strcmp( lhs, rhs ) < 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<const char*, function_type, cstr_compare> function_map_type;
|
typedef std::map<const char*, function_type, cstr_compare> function_map_type;
|
||||||
@@ -77,4 +70,4 @@ private:
|
|||||||
|
|
||||||
} // namespace osc
|
} // namespace osc
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H */
|
#endif /* INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H */
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
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
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
@@ -23,19 +27,8 @@
|
|||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#ifndef INCLUDED_OSC_EXCEPTION_H
|
||||||
/*
|
#define INCLUDED_OSC_EXCEPTION_H
|
||||||
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_OSCEXCEPTION_H
|
|
||||||
#define INCLUDED_OSCPACK_OSCEXCEPTION_H
|
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
@@ -47,8 +40,7 @@ class Exception : public std::exception {
|
|||||||
public:
|
public:
|
||||||
Exception() throw() {}
|
Exception() throw() {}
|
||||||
Exception( const Exception& src ) throw()
|
Exception( const Exception& src ) throw()
|
||||||
: std::exception( src )
|
: what_( src.what_ ) {}
|
||||||
, what_( src.what_ ) {}
|
|
||||||
Exception( const char *w ) throw()
|
Exception( const char *w ) throw()
|
||||||
: what_( w ) {}
|
: what_( w ) {}
|
||||||
Exception& operator=( const Exception& src ) throw()
|
Exception& operator=( const Exception& src ) throw()
|
||||||
@@ -59,4 +51,4 @@ public:
|
|||||||
|
|
||||||
} // namespace osc
|
} // namespace osc
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCEXCEPTION_H */
|
#endif /* INCLUDED_OSC_EXCEPTION_H */
|
||||||
63
ext/OSCPack/osc/OscHostEndianness.h
Normal file
63
ext/OSCPack/osc/OscHostEndianness.h
Normal 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
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
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
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
@@ -23,37 +27,18 @@
|
|||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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 "OscOutboundPacketStream.h"
|
#include "OscOutboundPacketStream.h"
|
||||||
|
|
||||||
#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32)
|
#include <string.h>
|
||||||
#include <malloc.h> // for alloca
|
#include <stdlib.h>
|
||||||
#else
|
#include <assert.h>
|
||||||
//#include <alloca.h> // alloca on Linux (also OSX)
|
|
||||||
#include <stdlib.h> // alloca on OSX and FreeBSD (and Linux?)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cassert>
|
#if defined(__WIN32__) || defined(WIN32)
|
||||||
#include <cstring> // memcpy, memmove, strcpy, strlen
|
#include <malloc.h> // for alloca
|
||||||
#include <cstddef> // ptrdiff_t
|
#endif
|
||||||
|
|
||||||
#include "OscHostEndianness.h"
|
#include "OscHostEndianness.h"
|
||||||
|
|
||||||
#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
|
|
||||||
namespace std {
|
|
||||||
using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'.
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace osc{
|
namespace osc{
|
||||||
|
|
||||||
@@ -145,14 +130,13 @@ static void FromUInt64( char *p, uint64 x )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// round up to the next highest multiple of 4. unless x is already a multiple of 4
|
static inline long RoundUp4( long x )
|
||||||
static inline std::size_t RoundUp4( std::size_t x )
|
|
||||||
{
|
{
|
||||||
return (x + 3) & ~((std::size_t)0x03);
|
return ((x-1) & (~0x03L)) + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity )
|
OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity )
|
||||||
: data_( buffer )
|
: data_( buffer )
|
||||||
, end_( data_ + capacity )
|
, end_( data_ + capacity )
|
||||||
, typeTagsCurrent_( end_ )
|
, typeTagsCurrent_( end_ )
|
||||||
@@ -161,12 +145,7 @@ OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity )
|
|||||||
, elementSizePtr_( 0 )
|
, elementSizePtr_( 0 )
|
||||||
, messageIsInProgress_( false )
|
, messageIsInProgress_( false )
|
||||||
{
|
{
|
||||||
// sanity check integer types declared in OscTypes.h
|
|
||||||
// you'll need to fix OscTypes.h if any of these asserts fail
|
|
||||||
assert( sizeof(osc::int32) == 4 );
|
|
||||||
assert( sizeof(osc::uint32) == 4 );
|
|
||||||
assert( sizeof(osc::int64) == 8 );
|
|
||||||
assert( sizeof(osc::uint64) == 8 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -210,15 +189,12 @@ void OutboundPacketStream::EndElement( char *endPtr )
|
|||||||
// size slot is stored in the elements size slot (or a ptr to data_
|
// size slot is stored in the elements size slot (or a ptr to data_
|
||||||
// if there is no containing element). We retrieve that here
|
// if there is no containing element). We retrieve that here
|
||||||
uint32 *previousElementSizePtr =
|
uint32 *previousElementSizePtr =
|
||||||
reinterpret_cast<uint32*>(data_ + *elementSizePtr_);
|
(uint32*)(data_ + *reinterpret_cast<uint32*>(elementSizePtr_));
|
||||||
|
|
||||||
// then we store the element size in the slot. note that the element
|
// then we store the element size in the slot, note that the element
|
||||||
// size does not include the size slot, hence the - 4 below.
|
// size does not include the size slot, hence the - 4 below.
|
||||||
|
uint32 elementSize =
|
||||||
std::ptrdiff_t d = endPtr - reinterpret_cast<char*>(elementSizePtr_);
|
(endPtr - reinterpret_cast<char*>(elementSizePtr_)) - 4;
|
||||||
// assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb
|
|
||||||
|
|
||||||
uint32 elementSize = static_cast<uint32>(d - 4);
|
|
||||||
FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
|
FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
|
||||||
|
|
||||||
// finally, we reset the element size ptr to the containing element
|
// finally, we reset the element size ptr to the containing element
|
||||||
@@ -235,7 +211,7 @@ bool OutboundPacketStream::ElementSizeSlotRequired() const
|
|||||||
|
|
||||||
void OutboundPacketStream::CheckForAvailableBundleSpace()
|
void OutboundPacketStream::CheckForAvailableBundleSpace()
|
||||||
{
|
{
|
||||||
std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
|
unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
|
||||||
|
|
||||||
if( required > Capacity() )
|
if( required > Capacity() )
|
||||||
throw OutOfBufferMemoryException();
|
throw OutOfBufferMemoryException();
|
||||||
@@ -245,18 +221,18 @@ void OutboundPacketStream::CheckForAvailableBundleSpace()
|
|||||||
void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern )
|
void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern )
|
||||||
{
|
{
|
||||||
// plus 4 for at least four bytes of type tag
|
// plus 4 for at least four bytes of type tag
|
||||||
std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0)
|
unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0)
|
||||||
+ RoundUp4(std::strlen(addressPattern) + 1) + 4;
|
+ RoundUp4(strlen(addressPattern) + 1) + 4;
|
||||||
|
|
||||||
if( required > Capacity() )
|
if( required > Capacity() )
|
||||||
throw OutOfBufferMemoryException();
|
throw OutOfBufferMemoryException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength )
|
void OutboundPacketStream::CheckForAvailableArgumentSpace( long argumentLength )
|
||||||
{
|
{
|
||||||
// plus three for extra type tag, comma and null terminator
|
// plus three for extra type tag, comma and null terminator
|
||||||
std::size_t required = (argumentCurrent_ - data_) + argumentLength
|
unsigned long required = (argumentCurrent_ - data_) + argumentLength
|
||||||
+ RoundUp4( (end_ - typeTagsCurrent_) + 3 );
|
+ RoundUp4( (end_ - typeTagsCurrent_) + 3 );
|
||||||
|
|
||||||
if( required > Capacity() )
|
if( required > Capacity() )
|
||||||
@@ -274,15 +250,15 @@ void OutboundPacketStream::Clear()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::size_t OutboundPacketStream::Capacity() const
|
unsigned int OutboundPacketStream::Capacity() const
|
||||||
{
|
{
|
||||||
return end_ - data_;
|
return end_ - data_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::size_t OutboundPacketStream::Size() const
|
unsigned int OutboundPacketStream::Size() const
|
||||||
{
|
{
|
||||||
std::size_t result = argumentCurrent_ - data_;
|
unsigned int result = argumentCurrent_ - data_;
|
||||||
if( IsMessageInProgress() ){
|
if( IsMessageInProgress() ){
|
||||||
// account for the length of the type tag string. the total type tag
|
// account for the length of the type tag string. the total type tag
|
||||||
// includes an initial comma, plus at least one terminating \0
|
// includes an initial comma, plus at least one terminating \0
|
||||||
@@ -326,7 +302,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& r
|
|||||||
|
|
||||||
messageCursor_ = BeginElement( messageCursor_ );
|
messageCursor_ = BeginElement( messageCursor_ );
|
||||||
|
|
||||||
std::memcpy( messageCursor_, "#bundle\0", 8 );
|
memcpy( messageCursor_, "#bundle\0", 8 );
|
||||||
FromUInt64( messageCursor_ + 8, rhs.timeTag );
|
FromUInt64( messageCursor_ + 8, rhs.timeTag );
|
||||||
|
|
||||||
messageCursor_ += 16;
|
messageCursor_ += 16;
|
||||||
@@ -360,12 +336,12 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs
|
|||||||
|
|
||||||
messageCursor_ = BeginElement( messageCursor_ );
|
messageCursor_ = BeginElement( messageCursor_ );
|
||||||
|
|
||||||
std::strcpy( messageCursor_, rhs.addressPattern );
|
strcpy( messageCursor_, rhs.addressPattern );
|
||||||
std::size_t rhsLength = std::strlen(rhs.addressPattern);
|
unsigned long rhsLength = strlen(rhs.addressPattern);
|
||||||
messageCursor_ += rhsLength + 1;
|
messageCursor_ += rhsLength + 1;
|
||||||
|
|
||||||
// zero pad to 4-byte boundary
|
// zero pad to 4-byte boundary
|
||||||
std::size_t i = rhsLength + 1;
|
unsigned long i = rhsLength + 1;
|
||||||
while( i & 0x3 ){
|
while( i & 0x3 ){
|
||||||
*messageCursor_++ = '\0';
|
*messageCursor_++ = '\0';
|
||||||
++i;
|
++i;
|
||||||
@@ -387,27 +363,27 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator&
|
|||||||
if( !IsMessageInProgress() )
|
if( !IsMessageInProgress() )
|
||||||
throw MessageNotInProgressException();
|
throw MessageNotInProgressException();
|
||||||
|
|
||||||
std::size_t typeTagsCount = end_ - typeTagsCurrent_;
|
int typeTagsCount = end_ - typeTagsCurrent_;
|
||||||
|
|
||||||
if( typeTagsCount ){
|
if( typeTagsCount ){
|
||||||
|
|
||||||
char *tempTypeTags = (char*)alloca(typeTagsCount);
|
char *tempTypeTags = (char*)alloca(typeTagsCount);
|
||||||
std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
|
memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
|
||||||
|
|
||||||
// slot size includes comma and null terminator
|
// slot size includes comma and null terminator
|
||||||
std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
|
int typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
|
||||||
|
|
||||||
std::size_t argumentsSize = argumentCurrent_ - messageCursor_;
|
uint32 argumentsSize = argumentCurrent_ - messageCursor_;
|
||||||
|
|
||||||
std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
|
memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
|
||||||
|
|
||||||
messageCursor_[0] = ',';
|
messageCursor_[0] = ',';
|
||||||
// copy type tags in reverse (really forward) order
|
// copy type tags in reverse (really forward) order
|
||||||
for( std::size_t i=0; i < typeTagsCount; ++i )
|
for( int i=0; i < typeTagsCount; ++i )
|
||||||
messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
|
messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
|
||||||
|
|
||||||
char *p = messageCursor_ + 1 + typeTagsCount;
|
char *p = messageCursor_ + 1 + typeTagsCount;
|
||||||
for( std::size_t i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )
|
for( int i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
|
|
||||||
typeTagsCurrent_ = end_;
|
typeTagsCurrent_ = end_;
|
||||||
@@ -417,7 +393,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator&
|
|||||||
|
|
||||||
}else{
|
}else{
|
||||||
// send an empty type tags string
|
// send an empty type tags string
|
||||||
std::memcpy( messageCursor_, ",\0\0\0", 4 );
|
memcpy( messageCursor_, ",\0\0\0", 4 );
|
||||||
|
|
||||||
// advance messageCursor_ for next message
|
// advance messageCursor_ for next message
|
||||||
messageCursor_ += 4;
|
messageCursor_ += 4;
|
||||||
@@ -599,15 +575,15 @@ OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
|
|||||||
|
|
||||||
OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
|
OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
|
||||||
{
|
{
|
||||||
CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
|
CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) );
|
||||||
|
|
||||||
*(--typeTagsCurrent_) = STRING_TYPE_TAG;
|
*(--typeTagsCurrent_) = STRING_TYPE_TAG;
|
||||||
std::strcpy( argumentCurrent_, rhs );
|
strcpy( argumentCurrent_, rhs );
|
||||||
std::size_t rhsLength = std::strlen(rhs);
|
unsigned long rhsLength = strlen(rhs);
|
||||||
argumentCurrent_ += rhsLength + 1;
|
argumentCurrent_ += rhsLength + 1;
|
||||||
|
|
||||||
// zero pad to 4-byte boundary
|
// zero pad to 4-byte boundary
|
||||||
std::size_t i = rhsLength + 1;
|
unsigned long i = rhsLength + 1;
|
||||||
while( i & 0x3 ){
|
while( i & 0x3 ){
|
||||||
*argumentCurrent_++ = '\0';
|
*argumentCurrent_++ = '\0';
|
||||||
++i;
|
++i;
|
||||||
@@ -619,15 +595,15 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
|
|||||||
|
|
||||||
OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
|
OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
|
||||||
{
|
{
|
||||||
CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
|
CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) );
|
||||||
|
|
||||||
*(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
|
*(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
|
||||||
std::strcpy( argumentCurrent_, rhs );
|
strcpy( argumentCurrent_, rhs );
|
||||||
std::size_t rhsLength = std::strlen(rhs);
|
unsigned long rhsLength = strlen(rhs);
|
||||||
argumentCurrent_ += rhsLength + 1;
|
argumentCurrent_ += rhsLength + 1;
|
||||||
|
|
||||||
// zero pad to 4-byte boundary
|
// zero pad to 4-byte boundary
|
||||||
std::size_t i = rhsLength + 1;
|
unsigned long i = rhsLength + 1;
|
||||||
while( i & 0x3 ){
|
while( i & 0x3 ){
|
||||||
*argumentCurrent_++ = '\0';
|
*argumentCurrent_++ = '\0';
|
||||||
++i;
|
++i;
|
||||||
@@ -645,7 +621,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
|
|||||||
FromUInt32( argumentCurrent_, rhs.size );
|
FromUInt32( argumentCurrent_, rhs.size );
|
||||||
argumentCurrent_ += 4;
|
argumentCurrent_ += 4;
|
||||||
|
|
||||||
std::memcpy( argumentCurrent_, rhs.data, rhs.size );
|
memcpy( argumentCurrent_, rhs.data, rhs.size );
|
||||||
argumentCurrent_ += rhs.size;
|
argumentCurrent_ += rhs.size;
|
||||||
|
|
||||||
// zero pad to 4-byte boundary
|
// zero pad to 4-byte boundary
|
||||||
@@ -658,26 +634,6 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs )
|
|
||||||
{
|
|
||||||
(void) rhs;
|
|
||||||
CheckForAvailableArgumentSpace(0);
|
|
||||||
|
|
||||||
*(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs )
|
|
||||||
{
|
|
||||||
(void) rhs;
|
|
||||||
CheckForAvailableArgumentSpace(0);
|
|
||||||
|
|
||||||
*(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace osc
|
} // namespace osc
|
||||||
|
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
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
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
@@ -23,21 +27,8 @@
|
|||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#ifndef INCLUDED_OSCOUTBOUNDPACKET_H
|
||||||
/*
|
#define INCLUDED_OSCOUTBOUNDPACKET_H
|
||||||
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_OSCOUTBOUNDPACKETSTREAM_H
|
|
||||||
#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H
|
|
||||||
|
|
||||||
#include <cstring> // size_t
|
|
||||||
|
|
||||||
#include "OscTypes.h"
|
#include "OscTypes.h"
|
||||||
#include "OscException.h"
|
#include "OscException.h"
|
||||||
@@ -75,15 +66,15 @@ public:
|
|||||||
|
|
||||||
class OutboundPacketStream{
|
class OutboundPacketStream{
|
||||||
public:
|
public:
|
||||||
OutboundPacketStream( char *buffer, std::size_t capacity );
|
OutboundPacketStream( char *buffer, unsigned long capacity );
|
||||||
~OutboundPacketStream();
|
~OutboundPacketStream();
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
std::size_t Capacity() const;
|
unsigned int Capacity() const;
|
||||||
|
|
||||||
// invariant: size() is valid even while building a message.
|
// invariant: size() is valid even while building a message.
|
||||||
std::size_t Size() const;
|
unsigned int Size() const;
|
||||||
|
|
||||||
const char *Data() const;
|
const char *Data() const;
|
||||||
|
|
||||||
@@ -105,7 +96,7 @@ public:
|
|||||||
OutboundPacketStream& operator<<( const InfinitumType& rhs );
|
OutboundPacketStream& operator<<( const InfinitumType& rhs );
|
||||||
OutboundPacketStream& operator<<( int32 rhs );
|
OutboundPacketStream& operator<<( int32 rhs );
|
||||||
|
|
||||||
#if !(defined(__x86_64__) || defined(_M_X64))
|
#ifndef x86_64
|
||||||
OutboundPacketStream& operator<<( int rhs )
|
OutboundPacketStream& operator<<( int rhs )
|
||||||
{ *this << (int32)rhs; return *this; }
|
{ *this << (int32)rhs; return *this; }
|
||||||
#endif
|
#endif
|
||||||
@@ -121,9 +112,6 @@ public:
|
|||||||
OutboundPacketStream& operator<<( const Symbol& rhs );
|
OutboundPacketStream& operator<<( const Symbol& rhs );
|
||||||
OutboundPacketStream& operator<<( const Blob& rhs );
|
OutboundPacketStream& operator<<( const Blob& rhs );
|
||||||
|
|
||||||
OutboundPacketStream& operator<<( const ArrayInitiator& rhs );
|
|
||||||
OutboundPacketStream& operator<<( const ArrayTerminator& rhs );
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
char *BeginElement( char *beginPtr );
|
char *BeginElement( char *beginPtr );
|
||||||
@@ -132,7 +120,7 @@ private:
|
|||||||
bool ElementSizeSlotRequired() const;
|
bool ElementSizeSlotRequired() const;
|
||||||
void CheckForAvailableBundleSpace();
|
void CheckForAvailableBundleSpace();
|
||||||
void CheckForAvailableMessageSpace( const char *addressPattern );
|
void CheckForAvailableMessageSpace( const char *addressPattern );
|
||||||
void CheckForAvailableArgumentSpace( std::size_t argumentLength );
|
void CheckForAvailableArgumentSpace( long argumentLength );
|
||||||
|
|
||||||
char *data_;
|
char *data_;
|
||||||
char *end_;
|
char *end_;
|
||||||
@@ -151,4 +139,4 @@ private:
|
|||||||
|
|
||||||
} // namespace osc
|
} // namespace osc
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H */
|
#endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
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
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
@@ -23,19 +27,8 @@
|
|||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#ifndef INCLUDED_OSCPACKETLISTENER_H
|
||||||
/*
|
#define INCLUDED_OSCPACKETLISTENER_H
|
||||||
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_OSCPACKETLISTENER_H
|
|
||||||
#define INCLUDED_OSCPACK_OSCPACKETLISTENER_H
|
|
||||||
|
|
||||||
#include "OscReceivedElements.h"
|
#include "OscReceivedElements.h"
|
||||||
#include "../ip/PacketListener.h"
|
#include "../ip/PacketListener.h"
|
||||||
@@ -76,4 +69,4 @@ public:
|
|||||||
|
|
||||||
} // namespace osc
|
} // namespace osc
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCPACKETLISTENER_H */
|
#endif /* INCLUDED_OSCPACKETLISTENER_H */
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
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
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
@@ -23,29 +27,13 @@
|
|||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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 "OscPrintReceivedElements.h"
|
#include "OscPrintReceivedElements.h"
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <ctime>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
|
|
||||||
namespace std {
|
|
||||||
using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'.
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace osc{
|
namespace osc{
|
||||||
|
|
||||||
@@ -121,17 +109,20 @@ std::ostream& operator<<( std::ostream & os,
|
|||||||
|
|
||||||
case TIME_TAG_TYPE_TAG:
|
case TIME_TAG_TYPE_TAG:
|
||||||
{
|
{
|
||||||
os << "OSC-timetag:" << arg.AsTimeTagUnchecked() << " ";
|
os << "OSC-timetag:" << arg.AsTimeTagUnchecked();
|
||||||
|
|
||||||
std::time_t t =
|
std::time_t t =
|
||||||
(unsigned long)( arg.AsTimeTagUnchecked() >> 32 );
|
(unsigned long)( arg.AsTimeTagUnchecked() >> 32 );
|
||||||
|
|
||||||
|
// strip trailing newline from string returned by ctime
|
||||||
const char *timeString = std::ctime( &t );
|
const char *timeString = std::ctime( &t );
|
||||||
size_t len = std::strlen( timeString );
|
size_t len = strlen( timeString );
|
||||||
|
char *s = new char[ len + 1 ];
|
||||||
|
strcpy( s, timeString );
|
||||||
|
if( len )
|
||||||
|
s[ len - 1 ] = '\0';
|
||||||
|
|
||||||
// -1 to omit trailing newline from string returned by ctime()
|
os << " " << s;
|
||||||
if( len > 1 )
|
|
||||||
os.write( timeString, len - 1 );
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -149,12 +140,12 @@ std::ostream& operator<<( std::ostream & os,
|
|||||||
|
|
||||||
case BLOB_TYPE_TAG:
|
case BLOB_TYPE_TAG:
|
||||||
{
|
{
|
||||||
|
unsigned long size;
|
||||||
const void *data;
|
const void *data;
|
||||||
osc_bundle_element_size_t size;
|
|
||||||
arg.AsBlobUnchecked( data, size );
|
arg.AsBlobUnchecked( data, size );
|
||||||
os << "OSC-blob:<<" << std::hex << std::setfill('0');
|
os << "OSC-blob:<<" << std::hex << std::setfill('0');
|
||||||
unsigned char *p = (unsigned char*)data;
|
unsigned char *p = (unsigned char*)data;
|
||||||
for( osc_bundle_element_size_t i = 0; i < size; ++i ){
|
for( unsigned long i = 0; i < size; ++i ){
|
||||||
os << "0x" << std::setw(2) << int(p[i]);
|
os << "0x" << std::setw(2) << int(p[i]);
|
||||||
if( i != size-1 )
|
if( i != size-1 )
|
||||||
os << ' ';
|
os << ' ';
|
||||||
@@ -164,14 +155,6 @@ std::ostream& operator<<( std::ostream & os,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ARRAY_BEGIN_TYPE_TAG:
|
|
||||||
os << "[";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ARRAY_END_TYPE_TAG:
|
|
||||||
os << "]";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
os << "unknown";
|
os << "unknown";
|
||||||
}
|
}
|
||||||
@@ -182,13 +165,10 @@ std::ostream& operator<<( std::ostream & os,
|
|||||||
|
|
||||||
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )
|
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )
|
||||||
{
|
{
|
||||||
os << "[";
|
|
||||||
if( m.AddressPatternIsUInt32() )
|
|
||||||
os << m.AddressPatternAsUInt32();
|
|
||||||
else
|
|
||||||
os << m.AddressPattern();
|
|
||||||
|
|
||||||
|
os << "[" << m.AddressPattern();
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
for( ReceivedMessage::const_iterator i = m.ArgumentsBegin();
|
for( ReceivedMessage::const_iterator i = m.ArgumentsBegin();
|
||||||
i != m.ArgumentsEnd(); ++i ){
|
i != m.ArgumentsEnd(); ++i ){
|
||||||
if( first ){
|
if( first ){
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
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
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
@@ -23,23 +27,14 @@
|
|||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
|
||||||
/*
|
#define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
|
||||||
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_OSCPRINTRECEIVEDELEMENTS_H
|
|
||||||
#define INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H
|
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
|
||||||
|
#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
|
||||||
#include "OscReceivedElements.h"
|
#include "OscReceivedElements.h"
|
||||||
|
#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
|
||||||
|
|
||||||
|
|
||||||
namespace osc{
|
namespace osc{
|
||||||
@@ -51,4 +46,4 @@ std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b );
|
|||||||
|
|
||||||
} // namespace osc
|
} // namespace osc
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H */
|
#endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */
|
||||||
722
ext/OSCPack/osc/OscReceivedElements.cpp
Normal file
722
ext/OSCPack/osc/OscReceivedElements.cpp
Normal 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
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
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
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
@@ -23,23 +27,8 @@
|
|||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
|
||||||
/*
|
#define INCLUDED_OSCRECEIVEDELEMENTS_H
|
||||||
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_OSCRECEIVEDELEMENTS_H
|
|
||||||
#define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstring> // size_t
|
|
||||||
|
|
||||||
#include "OscTypes.h"
|
#include "OscTypes.h"
|
||||||
#include "OscException.h"
|
#include "OscException.h"
|
||||||
@@ -48,12 +37,6 @@
|
|||||||
namespace osc{
|
namespace osc{
|
||||||
|
|
||||||
|
|
||||||
class MalformedPacketException : public Exception{
|
|
||||||
public:
|
|
||||||
MalformedPacketException( const char *w="malformed packet" )
|
|
||||||
: Exception( w ) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MalformedMessageException : public Exception{
|
class MalformedMessageException : public Exception{
|
||||||
public:
|
public:
|
||||||
MalformedMessageException( const char *w="malformed message" )
|
MalformedMessageException( const char *w="malformed message" )
|
||||||
@@ -87,73 +70,37 @@ public:
|
|||||||
|
|
||||||
class ReceivedPacket{
|
class ReceivedPacket{
|
||||||
public:
|
public:
|
||||||
// Although the OSC spec is not entirely clear on this, we only support
|
ReceivedPacket( const char *contents, int32 size )
|
||||||
// packets up to 0x7FFFFFFC bytes long (the maximum 4-byte aligned value
|
|
||||||
// representable by an int32). An exception will be raised if you pass a
|
|
||||||
// larger value to the ReceivedPacket() constructor.
|
|
||||||
|
|
||||||
ReceivedPacket( const char *contents, osc_bundle_element_size_t size )
|
|
||||||
: contents_( contents )
|
: contents_( contents )
|
||||||
, size_( ValidateSize(size) ) {}
|
, size_( size ) {}
|
||||||
|
|
||||||
ReceivedPacket( const char *contents, std::size_t size )
|
|
||||||
: contents_( contents )
|
|
||||||
, size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {}
|
|
||||||
|
|
||||||
#if !(defined(__x86_64__) || defined(_M_X64))
|
|
||||||
ReceivedPacket( const char *contents, int size )
|
|
||||||
: contents_( contents )
|
|
||||||
, size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool IsMessage() const { return !IsBundle(); }
|
bool IsMessage() const { return !IsBundle(); }
|
||||||
bool IsBundle() const;
|
bool IsBundle() const;
|
||||||
|
|
||||||
osc_bundle_element_size_t Size() const { return size_; }
|
int32 Size() const { return size_; }
|
||||||
const char *Contents() const { return contents_; }
|
const char *Contents() const { return contents_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *contents_;
|
const char *contents_;
|
||||||
osc_bundle_element_size_t size_;
|
int32 size_;
|
||||||
|
|
||||||
static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size )
|
|
||||||
{
|
|
||||||
// sanity check integer types declared in OscTypes.h
|
|
||||||
// you'll need to fix OscTypes.h if any of these asserts fail
|
|
||||||
assert( sizeof(osc::int32) == 4 );
|
|
||||||
assert( sizeof(osc::uint32) == 4 );
|
|
||||||
assert( sizeof(osc::int64) == 8 );
|
|
||||||
assert( sizeof(osc::uint64) == 8 );
|
|
||||||
|
|
||||||
if( !IsValidElementSizeValue(size) )
|
|
||||||
throw MalformedPacketException( "invalid packet size" );
|
|
||||||
|
|
||||||
if( size == 0 )
|
|
||||||
throw MalformedPacketException( "zero length elements not permitted" );
|
|
||||||
|
|
||||||
if( !IsMultipleOf4(size) )
|
|
||||||
throw MalformedPacketException( "element size must be multiple of four" );
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class ReceivedBundleElement{
|
class ReceivedBundleElement{
|
||||||
public:
|
public:
|
||||||
ReceivedBundleElement( const char *sizePtr )
|
ReceivedBundleElement( const char *size )
|
||||||
: sizePtr_( sizePtr ) {}
|
: size_( size ) {}
|
||||||
|
|
||||||
friend class ReceivedBundleElementIterator;
|
friend class ReceivedBundleElementIterator;
|
||||||
|
|
||||||
bool IsMessage() const { return !IsBundle(); }
|
bool IsMessage() const { return !IsBundle(); }
|
||||||
bool IsBundle() const;
|
bool IsBundle() const;
|
||||||
|
|
||||||
osc_bundle_element_size_t Size() const;
|
int32 Size() const;
|
||||||
const char *Contents() const { return sizePtr_ + osc::OSC_SIZEOF_INT32; }
|
const char *Contents() const { return size_ + 4; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *sizePtr_;
|
const char *size_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -185,11 +132,11 @@ public:
|
|||||||
private:
|
private:
|
||||||
ReceivedBundleElement value_;
|
ReceivedBundleElement value_;
|
||||||
|
|
||||||
void Advance() { value_.sizePtr_ = value_.Contents() + value_.Size(); }
|
void Advance() { value_.size_ = value_.Contents() + value_.Size(); }
|
||||||
|
|
||||||
bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const
|
bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const
|
||||||
{
|
{
|
||||||
return value_.sizePtr_ == rhs.value_.sizePtr_;
|
return value_.size_ == rhs.value_.size_;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -208,79 +155,73 @@ inline bool operator!=(const ReceivedBundleElementIterator& lhs,
|
|||||||
|
|
||||||
class ReceivedMessageArgument{
|
class ReceivedMessageArgument{
|
||||||
public:
|
public:
|
||||||
ReceivedMessageArgument( const char *typeTagPtr, const char *argumentPtr )
|
ReceivedMessageArgument( const char *typeTag, const char *argument )
|
||||||
: typeTagPtr_( typeTagPtr )
|
: typeTag_( typeTag )
|
||||||
, argumentPtr_( argumentPtr ) {}
|
, argument_( argument ) {}
|
||||||
|
|
||||||
friend class ReceivedMessageArgumentIterator;
|
friend class ReceivedMessageArgumentIterator;
|
||||||
|
|
||||||
char TypeTag() const { return *typeTagPtr_; }
|
const char TypeTag() const { return *typeTag_; }
|
||||||
|
|
||||||
// the unchecked methods below don't check whether the argument actually
|
// the unchecked methods below don't check whether the argument actually
|
||||||
// is of the specified type. they should only be used if you've already
|
// is of the specified type. they should only be used if you've already
|
||||||
// checked the type tag or the associated IsType() method.
|
// checked the type tag or the associated IsType() method.
|
||||||
|
|
||||||
bool IsBool() const
|
bool IsBool() const
|
||||||
{ return *typeTagPtr_ == TRUE_TYPE_TAG || *typeTagPtr_ == FALSE_TYPE_TAG; }
|
{ return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; }
|
||||||
bool AsBool() const;
|
bool AsBool() const;
|
||||||
bool AsBoolUnchecked() const;
|
bool AsBoolUnchecked() const;
|
||||||
|
|
||||||
bool IsNil() const { return *typeTagPtr_ == NIL_TYPE_TAG; }
|
bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; }
|
||||||
bool IsInfinitum() const { return *typeTagPtr_ == INFINITUM_TYPE_TAG; }
|
bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; }
|
||||||
|
|
||||||
bool IsInt32() const { return *typeTagPtr_ == INT32_TYPE_TAG; }
|
bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; }
|
||||||
int32 AsInt32() const;
|
int32 AsInt32() const;
|
||||||
int32 AsInt32Unchecked() const;
|
int32 AsInt32Unchecked() const;
|
||||||
|
|
||||||
bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; }
|
bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; }
|
||||||
float AsFloat() const;
|
float AsFloat() const;
|
||||||
float AsFloatUnchecked() const;
|
float AsFloatUnchecked() const;
|
||||||
|
|
||||||
bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; }
|
bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; }
|
||||||
char AsChar() const;
|
char AsChar() const;
|
||||||
char AsCharUnchecked() const;
|
char AsCharUnchecked() const;
|
||||||
|
|
||||||
bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; }
|
bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; }
|
||||||
uint32 AsRgbaColor() const;
|
uint32 AsRgbaColor() const;
|
||||||
uint32 AsRgbaColorUnchecked() const;
|
uint32 AsRgbaColorUnchecked() const;
|
||||||
|
|
||||||
bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; }
|
bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; }
|
||||||
uint32 AsMidiMessage() const;
|
uint32 AsMidiMessage() const;
|
||||||
uint32 AsMidiMessageUnchecked() const;
|
uint32 AsMidiMessageUnchecked() const;
|
||||||
|
|
||||||
bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; }
|
bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; }
|
||||||
int64 AsInt64() const;
|
int64 AsInt64() const;
|
||||||
int64 AsInt64Unchecked() const;
|
int64 AsInt64Unchecked() const;
|
||||||
|
|
||||||
bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; }
|
bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; }
|
||||||
uint64 AsTimeTag() const;
|
uint64 AsTimeTag() const;
|
||||||
uint64 AsTimeTagUnchecked() const;
|
uint64 AsTimeTagUnchecked() const;
|
||||||
|
|
||||||
bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; }
|
bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; }
|
||||||
double AsDouble() const;
|
double AsDouble() const;
|
||||||
double AsDoubleUnchecked() const;
|
double AsDoubleUnchecked() const;
|
||||||
|
|
||||||
bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; }
|
bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; }
|
||||||
const char* AsString() const;
|
const char* AsString() const;
|
||||||
const char* AsStringUnchecked() const { return argumentPtr_; }
|
const char* AsStringUnchecked() const { return argument_; }
|
||||||
|
|
||||||
bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; }
|
bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; }
|
||||||
const char* AsSymbol() const;
|
const char* AsSymbol() const;
|
||||||
const char* AsSymbolUnchecked() const { return argumentPtr_; }
|
const char* AsSymbolUnchecked() const { return argument_; }
|
||||||
|
|
||||||
bool IsBlob() const { return *typeTagPtr_ == BLOB_TYPE_TAG; }
|
bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; }
|
||||||
void AsBlob( const void*& data, osc_bundle_element_size_t& size ) const;
|
void AsBlob( const void*& data, unsigned long& size ) const;
|
||||||
void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const;
|
void AsBlobUnchecked( const void*& data, unsigned long& size ) const;
|
||||||
|
|
||||||
bool IsArrayBegin() const { return *typeTagPtr_ == ARRAY_BEGIN_TYPE_TAG; }
|
|
||||||
bool IsArrayEnd() const { return *typeTagPtr_ == ARRAY_END_TYPE_TAG; }
|
|
||||||
// Calculate the number of top-level items in the array. Nested arrays count as one item.
|
|
||||||
// Only valid at array start. Will throw an exception if IsArrayStart() == false.
|
|
||||||
std::size_t ComputeArrayItemCount() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *typeTagPtr_;
|
const char *typeTag_;
|
||||||
const char *argumentPtr_;
|
const char *argument_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -316,7 +257,7 @@ private:
|
|||||||
|
|
||||||
bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const
|
bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const
|
||||||
{
|
{
|
||||||
return value_.typeTagPtr_ == rhs.value_.typeTagPtr_;
|
return value_.typeTag_ == rhs.value_.typeTag_;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -358,7 +299,6 @@ public:
|
|||||||
|
|
||||||
// not sure if it would be useful to stream Nil and Infinitum
|
// not sure if it would be useful to stream Nil and Infinitum
|
||||||
// for now it's not possible
|
// for now it's not possible
|
||||||
// same goes for array boundaries
|
|
||||||
|
|
||||||
ReceivedMessageArgumentStream& operator>>( int32& rhs )
|
ReceivedMessageArgumentStream& operator>>( int32& rhs )
|
||||||
{
|
{
|
||||||
@@ -461,8 +401,6 @@ public:
|
|||||||
|
|
||||||
ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs )
|
ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs )
|
||||||
{
|
{
|
||||||
(void) rhs; // suppress unused parameter warning
|
|
||||||
|
|
||||||
if( !Eos() )
|
if( !Eos() )
|
||||||
throw ExcessArgumentException();
|
throw ExcessArgumentException();
|
||||||
|
|
||||||
@@ -472,18 +410,18 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
class ReceivedMessage{
|
class ReceivedMessage{
|
||||||
void Init( const char *bundle, osc_bundle_element_size_t size );
|
void Init( const char *bundle, unsigned long size );
|
||||||
public:
|
public:
|
||||||
explicit ReceivedMessage( const ReceivedPacket& packet );
|
explicit ReceivedMessage( const ReceivedPacket& packet );
|
||||||
explicit ReceivedMessage( const ReceivedBundleElement& bundleElement );
|
explicit ReceivedMessage( const ReceivedBundleElement& bundleElement );
|
||||||
|
|
||||||
const char *AddressPattern() const { return addressPattern_; }
|
const char *AddressPattern() const { return addressPattern_; }
|
||||||
|
|
||||||
// Support for non-standard SuperCollider integer address patterns:
|
// Support for non-standad SuperCollider integer address patterns:
|
||||||
bool AddressPatternIsUInt32() const;
|
bool AddressPatternIsUInt32() const;
|
||||||
uint32 AddressPatternAsUInt32() const;
|
uint32 AddressPatternAsUInt32() const;
|
||||||
|
|
||||||
uint32 ArgumentCount() const { return static_cast<uint32>(typeTagsEnd_ - typeTagsBegin_); }
|
unsigned long ArgumentCount() const { return static_cast<unsigned long>(typeTagsEnd_ - typeTagsBegin_); }
|
||||||
|
|
||||||
const char *TypeTags() const { return typeTagsBegin_; }
|
const char *TypeTags() const { return typeTagsBegin_; }
|
||||||
|
|
||||||
@@ -514,14 +452,14 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
class ReceivedBundle{
|
class ReceivedBundle{
|
||||||
void Init( const char *message, osc_bundle_element_size_t size );
|
void Init( const char *message, unsigned long size );
|
||||||
public:
|
public:
|
||||||
explicit ReceivedBundle( const ReceivedPacket& packet );
|
explicit ReceivedBundle( const ReceivedPacket& packet );
|
||||||
explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );
|
explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );
|
||||||
|
|
||||||
uint64 TimeTag() const;
|
uint64 TimeTag() const;
|
||||||
|
|
||||||
uint32 ElementCount() const { return elementCount_; }
|
unsigned long ElementCount() const { return elementCount_; }
|
||||||
|
|
||||||
typedef ReceivedBundleElementIterator const_iterator;
|
typedef ReceivedBundleElementIterator const_iterator;
|
||||||
|
|
||||||
@@ -538,11 +476,11 @@ public:
|
|||||||
private:
|
private:
|
||||||
const char *timeTag_;
|
const char *timeTag_;
|
||||||
const char *end_;
|
const char *end_;
|
||||||
uint32 elementCount_;
|
unsigned long elementCount_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace osc
|
} // namespace osc
|
||||||
|
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */
|
#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
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
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
@@ -23,17 +27,6 @@
|
|||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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 "OscTypes.h"
|
#include "OscTypes.h"
|
||||||
|
|
||||||
namespace osc{
|
namespace osc{
|
||||||
@@ -41,12 +34,7 @@ namespace osc{
|
|||||||
BundleInitiator BeginBundleImmediate(1);
|
BundleInitiator BeginBundleImmediate(1);
|
||||||
BundleTerminator EndBundle;
|
BundleTerminator EndBundle;
|
||||||
MessageTerminator EndMessage;
|
MessageTerminator EndMessage;
|
||||||
NilType OscNil;
|
NilType Nil;
|
||||||
#ifndef _OBJC_OBJC_H_
|
|
||||||
NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead
|
|
||||||
#endif
|
|
||||||
InfinitumType Infinitum;
|
InfinitumType Infinitum;
|
||||||
ArrayInitiator BeginArray;
|
|
||||||
ArrayTerminator EndArray;
|
|
||||||
|
|
||||||
} // namespace osc
|
} // namespace osc
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
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
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
@@ -23,19 +27,8 @@
|
|||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#ifndef INCLUDED_OSCTYPES_H
|
||||||
/*
|
#define INCLUDED_OSCTYPES_H
|
||||||
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_OSCTYPES_H
|
|
||||||
#define INCLUDED_OSCPACK_OSCTYPES_H
|
|
||||||
|
|
||||||
|
|
||||||
namespace osc{
|
namespace osc{
|
||||||
@@ -47,11 +40,6 @@ namespace osc{
|
|||||||
typedef __int64 int64;
|
typedef __int64 int64;
|
||||||
typedef unsigned __int64 uint64;
|
typedef unsigned __int64 uint64;
|
||||||
|
|
||||||
#elif defined(__x86_64__) || defined(_M_X64)
|
|
||||||
|
|
||||||
typedef long int64;
|
|
||||||
typedef unsigned long uint64;
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
typedef long long int64;
|
typedef long long int64;
|
||||||
@@ -61,7 +49,7 @@ typedef unsigned long long uint64;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__x86_64__) || defined(_M_X64)
|
#ifdef x86_64
|
||||||
|
|
||||||
typedef signed int int32;
|
typedef signed int int32;
|
||||||
typedef unsigned int uint32;
|
typedef unsigned int uint32;
|
||||||
@@ -74,41 +62,6 @@ typedef unsigned long uint32;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
enum ValueTypeSizes{
|
|
||||||
OSC_SIZEOF_INT32 = 4,
|
|
||||||
OSC_SIZEOF_UINT32 = 4,
|
|
||||||
OSC_SIZEOF_INT64 = 8,
|
|
||||||
OSC_SIZEOF_UINT64 = 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// are always positive since negative field sizes make no sense.
|
|
||||||
|
|
||||||
typedef int32 osc_bundle_element_size_t;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
OSC_INT32_MAX = 0x7FFFFFFF,
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
OSC_BUNDLE_ELEMENT_SIZE_MAX = 0x7FFFFFFC
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
inline bool IsValidElementSizeValue( osc_bundle_element_size_t x )
|
|
||||||
{
|
|
||||||
// sizes may not be negative or exceed OSC_BUNDLE_ELEMENT_SIZE_MAX
|
|
||||||
return x >= 0 && x <= OSC_BUNDLE_ELEMENT_SIZE_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool IsMultipleOf4( osc_bundle_element_size_t x )
|
|
||||||
{
|
|
||||||
return (x & ((osc_bundle_element_size_t)0x03)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
enum TypeTagValues {
|
enum TypeTagValues {
|
||||||
TRUE_TYPE_TAG = 'T',
|
TRUE_TYPE_TAG = 'T',
|
||||||
@@ -125,9 +78,7 @@ enum TypeTagValues {
|
|||||||
DOUBLE_TYPE_TAG = 'd',
|
DOUBLE_TYPE_TAG = 'd',
|
||||||
STRING_TYPE_TAG = 's',
|
STRING_TYPE_TAG = 's',
|
||||||
SYMBOL_TYPE_TAG = 'S',
|
SYMBOL_TYPE_TAG = 'S',
|
||||||
BLOB_TYPE_TAG = 'b',
|
BLOB_TYPE_TAG = 'b'
|
||||||
ARRAY_BEGIN_TYPE_TAG = '[',
|
|
||||||
ARRAY_END_TYPE_TAG = ']'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -169,11 +120,8 @@ extern MessageTerminator EndMessage;
|
|||||||
struct NilType{
|
struct NilType{
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NilType OscNil;
|
extern NilType Nil;
|
||||||
|
|
||||||
#ifndef _OBJC_OBJC_H_
|
|
||||||
extern NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct InfinitumType{
|
struct InfinitumType{
|
||||||
};
|
};
|
||||||
@@ -218,23 +166,13 @@ struct Symbol{
|
|||||||
|
|
||||||
struct Blob{
|
struct Blob{
|
||||||
Blob() {}
|
Blob() {}
|
||||||
explicit Blob( const void* data_, osc_bundle_element_size_t size_ )
|
explicit Blob( const void* data_, unsigned long size_ )
|
||||||
: data( data_ ), size( size_ ) {}
|
: data( data_ ), size( size_ ) {}
|
||||||
const void* data;
|
const void* data;
|
||||||
osc_bundle_element_size_t size;
|
unsigned long size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ArrayInitiator{
|
|
||||||
};
|
|
||||||
|
|
||||||
extern ArrayInitiator BeginArray;
|
|
||||||
|
|
||||||
struct ArrayTerminator{
|
|
||||||
};
|
|
||||||
|
|
||||||
extern ArrayTerminator EndArray;
|
|
||||||
|
|
||||||
} // namespace osc
|
} // namespace osc
|
||||||
|
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCTYPES_H */
|
#endif /* INCLUDED_OSCTYPES_H */
|
||||||
Reference in New Issue
Block a user