mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-05 15:30:00 +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,80 +1,73 @@
|
|||||||
/*
|
/*
|
||||||
oscpack -- Open Sound Control (OSC) packet manipulation library
|
oscpack -- Open Sound Control packet manipulation library
|
||||||
http://www.rossbencina.com/code/oscpack
|
http://www.audiomulch.com/~rossb/oscpack
|
||||||
|
|
||||||
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
|
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files
|
a copy of this software and associated documentation files
|
||||||
(the "Software"), to deal in the Software without restriction,
|
(the "Software"), to deal in the Software without restriction,
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
including without limitation the rights to use, copy, modify, merge,
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
and to permit persons to whom the Software is furnished to do so,
|
||||||
subject to the following conditions:
|
subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
The above copyright notice and this permission notice shall be
|
||||||
included in all copies or substantial portions of the Software.
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Any person wishing to distribute modifications to the Software is
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
requested to send the modifications to the original developer so that
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
they can be incorporated into the canonical version.
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
*/
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
/*
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
The text above constitutes the entire oscpack license; however,
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
the oscpack developer(s) also make the following non-binding requests:
|
*/
|
||||||
|
#ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
|
||||||
Any person wishing to distribute modifications to the Software is
|
#define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
|
||||||
requested to send the modifications to the original developer so that
|
|
||||||
they can be incorporated into the canonical version. It is also
|
#include <string.h>
|
||||||
requested that these non-binding requests be included whenever the
|
#include <map>
|
||||||
above license is reproduced.
|
|
||||||
*/
|
#include "OscPacketListener.h"
|
||||||
#ifndef INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H
|
|
||||||
#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H
|
|
||||||
|
|
||||||
#include <cstring>
|
namespace osc{
|
||||||
#include <map>
|
|
||||||
|
template< class T >
|
||||||
#include "OscPacketListener.h"
|
class MessageMappingOscPacketListener : public OscPacketListener{
|
||||||
|
public:
|
||||||
|
typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&);
|
||||||
|
|
||||||
namespace osc{
|
protected:
|
||||||
|
void RegisterMessageFunction( const char *addressPattern, function_type f )
|
||||||
template< class T >
|
{
|
||||||
class MessageMappingOscPacketListener : public OscPacketListener{
|
functions_.insert( std::make_pair( addressPattern, f ) );
|
||||||
public:
|
}
|
||||||
typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&);
|
|
||||||
|
virtual void ProcessMessage( const osc::ReceivedMessage& m,
|
||||||
protected:
|
const IpEndpointName& remoteEndpoint )
|
||||||
void RegisterMessageFunction( const char *addressPattern, function_type f )
|
{
|
||||||
{
|
typename function_map_type::iterator i = functions_.find( m.AddressPattern() );
|
||||||
functions_.insert( std::make_pair( addressPattern, f ) );
|
if( i != functions_.end() )
|
||||||
}
|
(dynamic_cast<T*>(this)->*(i->second))( m, remoteEndpoint );
|
||||||
|
}
|
||||||
virtual void ProcessMessage( const osc::ReceivedMessage& m,
|
|
||||||
const IpEndpointName& remoteEndpoint )
|
private:
|
||||||
{
|
struct cstr_compare{
|
||||||
typename function_map_type::iterator i = functions_.find( m.AddressPattern() );
|
bool operator()( const char *lhs, const char *rhs ) const
|
||||||
if( i != functions_.end() )
|
{ return strcmp( lhs, rhs ) < 0; }
|
||||||
(dynamic_cast<T*>(this)->*(i->second))( m, remoteEndpoint );
|
};
|
||||||
}
|
|
||||||
|
typedef std::map<const char*, function_type, cstr_compare> function_map_type;
|
||||||
private:
|
function_map_type functions_;
|
||||||
struct cstr_compare{
|
};
|
||||||
bool operator()( const char *lhs, const char *rhs ) const
|
|
||||||
{ return std::strcmp( lhs, rhs ) < 0; }
|
} // namespace osc
|
||||||
};
|
|
||||||
|
#endif /* INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H */
|
||||||
typedef std::map<const char*, function_type, cstr_compare> function_map_type;
|
|
||||||
function_map_type functions_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace osc
|
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H */
|
|
||||||
@@ -1,62 +1,54 @@
|
|||||||
/*
|
/*
|
||||||
oscpack -- Open Sound Control (OSC) packet manipulation library
|
oscpack -- Open Sound Control packet manipulation library
|
||||||
http://www.rossbencina.com/code/oscpack
|
http://www.audiomulch.com/~rossb/oscpack
|
||||||
|
|
||||||
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
|
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files
|
a copy of this software and associated documentation files
|
||||||
(the "Software"), to deal in the Software without restriction,
|
(the "Software"), to deal in the Software without restriction,
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
including without limitation the rights to use, copy, modify, merge,
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
and to permit persons to whom the Software is furnished to do so,
|
||||||
subject to the following conditions:
|
subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
The above copyright notice and this permission notice shall be
|
||||||
included in all copies or substantial portions of the Software.
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Any person wishing to distribute modifications to the Software is
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
requested to send the modifications to the original developer so that
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
they can be incorporated into the canonical version.
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
*/
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
/*
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
The text above constitutes the entire oscpack license; however,
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
the oscpack developer(s) also make the following non-binding requests:
|
*/
|
||||||
|
#ifndef INCLUDED_OSC_EXCEPTION_H
|
||||||
Any person wishing to distribute modifications to the Software is
|
#define INCLUDED_OSC_EXCEPTION_H
|
||||||
requested to send the modifications to the original developer so that
|
|
||||||
they can be incorporated into the canonical version. It is also
|
#include <exception>
|
||||||
requested that these non-binding requests be included whenever the
|
|
||||||
above license is reproduced.
|
namespace osc{
|
||||||
*/
|
|
||||||
#ifndef INCLUDED_OSCPACK_OSCEXCEPTION_H
|
class Exception : public std::exception {
|
||||||
#define INCLUDED_OSCPACK_OSCEXCEPTION_H
|
const char *what_;
|
||||||
|
|
||||||
#include <exception>
|
public:
|
||||||
|
Exception() throw() {}
|
||||||
namespace osc{
|
Exception( const Exception& src ) throw()
|
||||||
|
: what_( src.what_ ) {}
|
||||||
class Exception : public std::exception {
|
Exception( const char *w ) throw()
|
||||||
const char *what_;
|
: what_( w ) {}
|
||||||
|
Exception& operator=( const Exception& src ) throw()
|
||||||
public:
|
{ what_ = src.what_; return *this; }
|
||||||
Exception() throw() {}
|
virtual ~Exception() throw() {}
|
||||||
Exception( const Exception& src ) throw()
|
virtual const char* what() const throw() { return what_; }
|
||||||
: std::exception( src )
|
};
|
||||||
, what_( src.what_ ) {}
|
|
||||||
Exception( const char *w ) throw()
|
} // namespace osc
|
||||||
: what_( w ) {}
|
|
||||||
Exception& operator=( const Exception& src ) throw()
|
#endif /* INCLUDED_OSC_EXCEPTION_H */
|
||||||
{ what_ = src.what_; return *this; }
|
|
||||||
virtual ~Exception() throw() {}
|
|
||||||
virtual const char* what() const throw() { return what_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace osc
|
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCEXCEPTION_H */
|
|
||||||
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
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,154 +1,142 @@
|
|||||||
/*
|
/*
|
||||||
oscpack -- Open Sound Control (OSC) packet manipulation library
|
oscpack -- Open Sound Control packet manipulation library
|
||||||
http://www.rossbencina.com/code/oscpack
|
http://www.audiomulch.com/~rossb/oscpack
|
||||||
|
|
||||||
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
|
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files
|
a copy of this software and associated documentation files
|
||||||
(the "Software"), to deal in the Software without restriction,
|
(the "Software"), to deal in the Software without restriction,
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
including without limitation the rights to use, copy, modify, merge,
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
and to permit persons to whom the Software is furnished to do so,
|
||||||
subject to the following conditions:
|
subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
The above copyright notice and this permission notice shall be
|
||||||
included in all copies or substantial portions of the Software.
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Any person wishing to distribute modifications to the Software is
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
requested to send the modifications to the original developer so that
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
they can be incorporated into the canonical version.
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
*/
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
/*
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
The text above constitutes the entire oscpack license; however,
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
the oscpack developer(s) also make the following non-binding requests:
|
*/
|
||||||
|
#ifndef INCLUDED_OSCOUTBOUNDPACKET_H
|
||||||
Any person wishing to distribute modifications to the Software is
|
#define INCLUDED_OSCOUTBOUNDPACKET_H
|
||||||
requested to send the modifications to the original developer so that
|
|
||||||
they can be incorporated into the canonical version. It is also
|
#include "OscTypes.h"
|
||||||
requested that these non-binding requests be included whenever the
|
#include "OscException.h"
|
||||||
above license is reproduced.
|
|
||||||
*/
|
|
||||||
#ifndef INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H
|
namespace osc{
|
||||||
#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H
|
|
||||||
|
class OutOfBufferMemoryException : public Exception{
|
||||||
#include <cstring> // size_t
|
public:
|
||||||
|
OutOfBufferMemoryException( const char *w="out of buffer memory" )
|
||||||
#include "OscTypes.h"
|
: Exception( w ) {}
|
||||||
#include "OscException.h"
|
};
|
||||||
|
|
||||||
|
class BundleNotInProgressException : public Exception{
|
||||||
namespace osc{
|
public:
|
||||||
|
BundleNotInProgressException(
|
||||||
class OutOfBufferMemoryException : public Exception{
|
const char *w="call to EndBundle when bundle is not in progress" )
|
||||||
public:
|
: Exception( w ) {}
|
||||||
OutOfBufferMemoryException( const char *w="out of buffer memory" )
|
};
|
||||||
: Exception( w ) {}
|
|
||||||
};
|
class MessageInProgressException : public Exception{
|
||||||
|
public:
|
||||||
class BundleNotInProgressException : public Exception{
|
MessageInProgressException(
|
||||||
public:
|
const char *w="opening or closing bundle or message while message is in progress" )
|
||||||
BundleNotInProgressException(
|
: Exception( w ) {}
|
||||||
const char *w="call to EndBundle when bundle is not in progress" )
|
};
|
||||||
: Exception( w ) {}
|
|
||||||
};
|
class MessageNotInProgressException : public Exception{
|
||||||
|
public:
|
||||||
class MessageInProgressException : public Exception{
|
MessageNotInProgressException(
|
||||||
public:
|
const char *w="call to EndMessage when message is not in progress" )
|
||||||
MessageInProgressException(
|
: Exception( w ) {}
|
||||||
const char *w="opening or closing bundle or message while message is in progress" )
|
};
|
||||||
: Exception( w ) {}
|
|
||||||
};
|
|
||||||
|
class OutboundPacketStream{
|
||||||
class MessageNotInProgressException : public Exception{
|
public:
|
||||||
public:
|
OutboundPacketStream( char *buffer, unsigned long capacity );
|
||||||
MessageNotInProgressException(
|
~OutboundPacketStream();
|
||||||
const char *w="call to EndMessage when message is not in progress" )
|
|
||||||
: Exception( w ) {}
|
void Clear();
|
||||||
};
|
|
||||||
|
unsigned int Capacity() const;
|
||||||
|
|
||||||
class OutboundPacketStream{
|
// invariant: size() is valid even while building a message.
|
||||||
public:
|
unsigned int Size() const;
|
||||||
OutboundPacketStream( char *buffer, std::size_t capacity );
|
|
||||||
~OutboundPacketStream();
|
const char *Data() const;
|
||||||
|
|
||||||
void Clear();
|
// indicates that all messages have been closed with a matching EndMessage
|
||||||
|
// and all bundles have been closed with a matching EndBundle
|
||||||
std::size_t Capacity() const;
|
bool IsReady() const;
|
||||||
|
|
||||||
// invariant: size() is valid even while building a message.
|
bool IsMessageInProgress() const;
|
||||||
std::size_t Size() const;
|
bool IsBundleInProgress() const;
|
||||||
|
|
||||||
const char *Data() const;
|
OutboundPacketStream& operator<<( const BundleInitiator& rhs );
|
||||||
|
OutboundPacketStream& operator<<( const BundleTerminator& rhs );
|
||||||
// indicates that all messages have been closed with a matching EndMessage
|
|
||||||
// and all bundles have been closed with a matching EndBundle
|
OutboundPacketStream& operator<<( const BeginMessage& rhs );
|
||||||
bool IsReady() const;
|
OutboundPacketStream& operator<<( const MessageTerminator& rhs );
|
||||||
|
|
||||||
bool IsMessageInProgress() const;
|
OutboundPacketStream& operator<<( bool rhs );
|
||||||
bool IsBundleInProgress() const;
|
OutboundPacketStream& operator<<( const NilType& rhs );
|
||||||
|
OutboundPacketStream& operator<<( const InfinitumType& rhs );
|
||||||
OutboundPacketStream& operator<<( const BundleInitiator& rhs );
|
OutboundPacketStream& operator<<( int32 rhs );
|
||||||
OutboundPacketStream& operator<<( const BundleTerminator& rhs );
|
|
||||||
|
#ifndef x86_64
|
||||||
OutboundPacketStream& operator<<( const BeginMessage& rhs );
|
OutboundPacketStream& operator<<( int rhs )
|
||||||
OutboundPacketStream& operator<<( const MessageTerminator& rhs );
|
{ *this << (int32)rhs; return *this; }
|
||||||
|
#endif
|
||||||
OutboundPacketStream& operator<<( bool rhs );
|
|
||||||
OutboundPacketStream& operator<<( const NilType& rhs );
|
OutboundPacketStream& operator<<( float rhs );
|
||||||
OutboundPacketStream& operator<<( const InfinitumType& rhs );
|
OutboundPacketStream& operator<<( char rhs );
|
||||||
OutboundPacketStream& operator<<( int32 rhs );
|
OutboundPacketStream& operator<<( const RgbaColor& rhs );
|
||||||
|
OutboundPacketStream& operator<<( const MidiMessage& rhs );
|
||||||
#if !(defined(__x86_64__) || defined(_M_X64))
|
OutboundPacketStream& operator<<( int64 rhs );
|
||||||
OutboundPacketStream& operator<<( int rhs )
|
OutboundPacketStream& operator<<( const TimeTag& rhs );
|
||||||
{ *this << (int32)rhs; return *this; }
|
OutboundPacketStream& operator<<( double rhs );
|
||||||
#endif
|
OutboundPacketStream& operator<<( const char* rhs );
|
||||||
|
OutboundPacketStream& operator<<( const Symbol& rhs );
|
||||||
OutboundPacketStream& operator<<( float rhs );
|
OutboundPacketStream& operator<<( const Blob& rhs );
|
||||||
OutboundPacketStream& operator<<( char rhs );
|
|
||||||
OutboundPacketStream& operator<<( const RgbaColor& rhs );
|
private:
|
||||||
OutboundPacketStream& operator<<( const MidiMessage& rhs );
|
|
||||||
OutboundPacketStream& operator<<( int64 rhs );
|
char *BeginElement( char *beginPtr );
|
||||||
OutboundPacketStream& operator<<( const TimeTag& rhs );
|
void EndElement( char *endPtr );
|
||||||
OutboundPacketStream& operator<<( double rhs );
|
|
||||||
OutboundPacketStream& operator<<( const char* rhs );
|
bool ElementSizeSlotRequired() const;
|
||||||
OutboundPacketStream& operator<<( const Symbol& rhs );
|
void CheckForAvailableBundleSpace();
|
||||||
OutboundPacketStream& operator<<( const Blob& rhs );
|
void CheckForAvailableMessageSpace( const char *addressPattern );
|
||||||
|
void CheckForAvailableArgumentSpace( long argumentLength );
|
||||||
OutboundPacketStream& operator<<( const ArrayInitiator& rhs );
|
|
||||||
OutboundPacketStream& operator<<( const ArrayTerminator& rhs );
|
char *data_;
|
||||||
|
char *end_;
|
||||||
private:
|
|
||||||
|
char *typeTagsCurrent_; // stored in reverse order
|
||||||
char *BeginElement( char *beginPtr );
|
char *messageCursor_;
|
||||||
void EndElement( char *endPtr );
|
char *argumentCurrent_;
|
||||||
|
|
||||||
bool ElementSizeSlotRequired() const;
|
// elementSizePtr_ has two special values: 0 indicates that a bundle
|
||||||
void CheckForAvailableBundleSpace();
|
// isn't open, and elementSizePtr_==data_ indicates that a bundle is
|
||||||
void CheckForAvailableMessageSpace( const char *addressPattern );
|
// open but that it doesn't have a size slot (ie the outermost bundle)
|
||||||
void CheckForAvailableArgumentSpace( std::size_t argumentLength );
|
uint32 *elementSizePtr_;
|
||||||
|
|
||||||
char *data_;
|
bool messageIsInProgress_;
|
||||||
char *end_;
|
};
|
||||||
|
|
||||||
char *typeTagsCurrent_; // stored in reverse order
|
} // namespace osc
|
||||||
char *messageCursor_;
|
|
||||||
char *argumentCurrent_;
|
#endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */
|
||||||
|
|
||||||
// elementSizePtr_ has two special values: 0 indicates that a bundle
|
|
||||||
// isn't open, and elementSizePtr_==data_ indicates that a bundle is
|
|
||||||
// open but that it doesn't have a size slot (ie the outermost bundle)
|
|
||||||
uint32 *elementSizePtr_;
|
|
||||||
|
|
||||||
bool messageIsInProgress_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace osc
|
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H */
|
|
||||||
@@ -1,79 +1,72 @@
|
|||||||
/*
|
/*
|
||||||
oscpack -- Open Sound Control (OSC) packet manipulation library
|
oscpack -- Open Sound Control packet manipulation library
|
||||||
http://www.rossbencina.com/code/oscpack
|
http://www.audiomulch.com/~rossb/oscpack
|
||||||
|
|
||||||
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
|
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files
|
a copy of this software and associated documentation files
|
||||||
(the "Software"), to deal in the Software without restriction,
|
(the "Software"), to deal in the Software without restriction,
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
including without limitation the rights to use, copy, modify, merge,
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
and to permit persons to whom the Software is furnished to do so,
|
||||||
subject to the following conditions:
|
subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
The above copyright notice and this permission notice shall be
|
||||||
included in all copies or substantial portions of the Software.
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Any person wishing to distribute modifications to the Software is
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
requested to send the modifications to the original developer so that
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
they can be incorporated into the canonical version.
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
*/
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
/*
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
The text above constitutes the entire oscpack license; however,
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
the oscpack developer(s) also make the following non-binding requests:
|
*/
|
||||||
|
#ifndef INCLUDED_OSCPACKETLISTENER_H
|
||||||
Any person wishing to distribute modifications to the Software is
|
#define INCLUDED_OSCPACKETLISTENER_H
|
||||||
requested to send the modifications to the original developer so that
|
|
||||||
they can be incorporated into the canonical version. It is also
|
#include "OscReceivedElements.h"
|
||||||
requested that these non-binding requests be included whenever the
|
#include "../ip/PacketListener.h"
|
||||||
above license is reproduced.
|
|
||||||
*/
|
|
||||||
#ifndef INCLUDED_OSCPACK_OSCPACKETLISTENER_H
|
namespace osc{
|
||||||
#define INCLUDED_OSCPACK_OSCPACKETLISTENER_H
|
|
||||||
|
class OscPacketListener : public PacketListener{
|
||||||
#include "OscReceivedElements.h"
|
protected:
|
||||||
#include "../ip/PacketListener.h"
|
virtual void ProcessBundle( const osc::ReceivedBundle& b,
|
||||||
|
const IpEndpointName& remoteEndpoint )
|
||||||
|
{
|
||||||
namespace osc{
|
// ignore bundle time tag for now
|
||||||
|
|
||||||
class OscPacketListener : public PacketListener{
|
for( ReceivedBundle::const_iterator i = b.ElementsBegin();
|
||||||
protected:
|
i != b.ElementsEnd(); ++i ){
|
||||||
virtual void ProcessBundle( const osc::ReceivedBundle& b,
|
if( i->IsBundle() )
|
||||||
const IpEndpointName& remoteEndpoint )
|
ProcessBundle( ReceivedBundle(*i), remoteEndpoint );
|
||||||
{
|
else
|
||||||
// ignore bundle time tag for now
|
ProcessMessage( ReceivedMessage(*i), remoteEndpoint );
|
||||||
|
}
|
||||||
for( ReceivedBundle::const_iterator i = b.ElementsBegin();
|
}
|
||||||
i != b.ElementsEnd(); ++i ){
|
|
||||||
if( i->IsBundle() )
|
virtual void ProcessMessage( const osc::ReceivedMessage& m,
|
||||||
ProcessBundle( ReceivedBundle(*i), remoteEndpoint );
|
const IpEndpointName& remoteEndpoint ) = 0;
|
||||||
else
|
|
||||||
ProcessMessage( ReceivedMessage(*i), remoteEndpoint );
|
public:
|
||||||
}
|
virtual void ProcessPacket( const char *data, int size,
|
||||||
}
|
const IpEndpointName& remoteEndpoint )
|
||||||
|
{
|
||||||
virtual void ProcessMessage( const osc::ReceivedMessage& m,
|
osc::ReceivedPacket p( data, size );
|
||||||
const IpEndpointName& remoteEndpoint ) = 0;
|
if( p.IsBundle() )
|
||||||
|
ProcessBundle( ReceivedBundle(p), remoteEndpoint );
|
||||||
public:
|
else
|
||||||
virtual void ProcessPacket( const char *data, int size,
|
ProcessMessage( ReceivedMessage(p), remoteEndpoint );
|
||||||
const IpEndpointName& remoteEndpoint )
|
}
|
||||||
{
|
};
|
||||||
osc::ReceivedPacket p( data, size );
|
|
||||||
if( p.IsBundle() )
|
} // namespace osc
|
||||||
ProcessBundle( ReceivedBundle(p), remoteEndpoint );
|
|
||||||
else
|
#endif /* INCLUDED_OSCPACKETLISTENER_H */
|
||||||
ProcessMessage( ReceivedMessage(p), remoteEndpoint );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace osc
|
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCPACKETLISTENER_H */
|
|
||||||
@@ -1,261 +1,241 @@
|
|||||||
/*
|
/*
|
||||||
oscpack -- Open Sound Control (OSC) packet manipulation library
|
oscpack -- Open Sound Control packet manipulation library
|
||||||
http://www.rossbencina.com/code/oscpack
|
http://www.audiomulch.com/~rossb/oscpack
|
||||||
|
|
||||||
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
|
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files
|
a copy of this software and associated documentation files
|
||||||
(the "Software"), to deal in the Software without restriction,
|
(the "Software"), to deal in the Software without restriction,
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
including without limitation the rights to use, copy, modify, merge,
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
and to permit persons to whom the Software is furnished to do so,
|
||||||
subject to the following conditions:
|
subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
The above copyright notice and this permission notice shall be
|
||||||
included in all copies or substantial portions of the Software.
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Any person wishing to distribute modifications to the Software is
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
requested to send the modifications to the original developer so that
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
they can be incorporated into the canonical version.
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
*/
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
/*
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
The text above constitutes the entire oscpack license; however,
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
the oscpack developer(s) also make the following non-binding requests:
|
*/
|
||||||
|
#include "OscPrintReceivedElements.h"
|
||||||
Any person wishing to distribute modifications to the Software is
|
|
||||||
requested to send the modifications to the original developer so that
|
#include <iostream>
|
||||||
they can be incorporated into the canonical version. It is also
|
#include <cstring>
|
||||||
requested that these non-binding requests be included whenever the
|
#include <iomanip>
|
||||||
above license is reproduced.
|
#include <ctime>
|
||||||
*/
|
|
||||||
#include "OscPrintReceivedElements.h"
|
|
||||||
|
namespace osc{
|
||||||
#include <cstring>
|
|
||||||
#include <ctime>
|
|
||||||
#include <iostream>
|
std::ostream& operator<<( std::ostream & os,
|
||||||
#include <iomanip>
|
const ReceivedMessageArgument& arg )
|
||||||
|
{
|
||||||
#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
|
switch( arg.TypeTag() ){
|
||||||
namespace std {
|
case TRUE_TYPE_TAG:
|
||||||
using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'.
|
os << "bool:true";
|
||||||
}
|
break;
|
||||||
#endif
|
|
||||||
|
case FALSE_TYPE_TAG:
|
||||||
namespace osc{
|
os << "bool:false";
|
||||||
|
break;
|
||||||
|
|
||||||
std::ostream& operator<<( std::ostream & os,
|
case NIL_TYPE_TAG:
|
||||||
const ReceivedMessageArgument& arg )
|
os << "(Nil)";
|
||||||
{
|
break;
|
||||||
switch( arg.TypeTag() ){
|
|
||||||
case TRUE_TYPE_TAG:
|
case INFINITUM_TYPE_TAG:
|
||||||
os << "bool:true";
|
os << "(Infinitum)";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FALSE_TYPE_TAG:
|
case INT32_TYPE_TAG:
|
||||||
os << "bool:false";
|
os << "int32:" << arg.AsInt32Unchecked();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NIL_TYPE_TAG:
|
case FLOAT_TYPE_TAG:
|
||||||
os << "(Nil)";
|
os << "float32:" << arg.AsFloatUnchecked();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INFINITUM_TYPE_TAG:
|
case CHAR_TYPE_TAG:
|
||||||
os << "(Infinitum)";
|
{
|
||||||
break;
|
char s[2] = {0};
|
||||||
|
s[0] = arg.AsCharUnchecked();
|
||||||
case INT32_TYPE_TAG:
|
os << "char:'" << s << "'";
|
||||||
os << "int32:" << arg.AsInt32Unchecked();
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FLOAT_TYPE_TAG:
|
case RGBA_COLOR_TYPE_TAG:
|
||||||
os << "float32:" << arg.AsFloatUnchecked();
|
{
|
||||||
break;
|
uint32 color = arg.AsRgbaColorUnchecked();
|
||||||
|
|
||||||
case CHAR_TYPE_TAG:
|
os << "RGBA:0x"
|
||||||
{
|
<< std::hex << std::setfill('0')
|
||||||
char s[2] = {0};
|
<< std::setw(2) << (int)((color>>24) & 0xFF)
|
||||||
s[0] = arg.AsCharUnchecked();
|
<< std::setw(2) << (int)((color>>16) & 0xFF)
|
||||||
os << "char:'" << s << "'";
|
<< std::setw(2) << (int)((color>>8) & 0xFF)
|
||||||
}
|
<< std::setw(2) << (int)(color & 0xFF)
|
||||||
break;
|
<< std::setfill(' ');
|
||||||
|
os.unsetf(std::ios::basefield);
|
||||||
case RGBA_COLOR_TYPE_TAG:
|
}
|
||||||
{
|
break;
|
||||||
uint32 color = arg.AsRgbaColorUnchecked();
|
|
||||||
|
case MIDI_MESSAGE_TYPE_TAG:
|
||||||
os << "RGBA:0x"
|
{
|
||||||
<< std::hex << std::setfill('0')
|
uint32 m = arg.AsMidiMessageUnchecked();
|
||||||
<< std::setw(2) << (int)((color>>24) & 0xFF)
|
os << "midi (port, status, data1, data2):<<"
|
||||||
<< std::setw(2) << (int)((color>>16) & 0xFF)
|
<< std::hex << std::setfill('0')
|
||||||
<< std::setw(2) << (int)((color>>8) & 0xFF)
|
<< "0x" << std::setw(2) << (int)((m>>24) & 0xFF)
|
||||||
<< std::setw(2) << (int)(color & 0xFF)
|
<< " 0x" << std::setw(2) << (int)((m>>16) & 0xFF)
|
||||||
<< std::setfill(' ');
|
<< " 0x" << std::setw(2) << (int)((m>>8) & 0xFF)
|
||||||
os.unsetf(std::ios::basefield);
|
<< " 0x" << std::setw(2) << (int)(m & 0xFF)
|
||||||
}
|
<< std::setfill(' ') << ">>";
|
||||||
break;
|
os.unsetf(std::ios::basefield);
|
||||||
|
}
|
||||||
case MIDI_MESSAGE_TYPE_TAG:
|
break;
|
||||||
{
|
|
||||||
uint32 m = arg.AsMidiMessageUnchecked();
|
case INT64_TYPE_TAG:
|
||||||
os << "midi (port, status, data1, data2):<<"
|
os << "int64:" << arg.AsInt64Unchecked();
|
||||||
<< std::hex << std::setfill('0')
|
break;
|
||||||
<< "0x" << std::setw(2) << (int)((m>>24) & 0xFF)
|
|
||||||
<< " 0x" << std::setw(2) << (int)((m>>16) & 0xFF)
|
case TIME_TAG_TYPE_TAG:
|
||||||
<< " 0x" << std::setw(2) << (int)((m>>8) & 0xFF)
|
{
|
||||||
<< " 0x" << std::setw(2) << (int)(m & 0xFF)
|
os << "OSC-timetag:" << arg.AsTimeTagUnchecked();
|
||||||
<< std::setfill(' ') << ">>";
|
|
||||||
os.unsetf(std::ios::basefield);
|
std::time_t t =
|
||||||
}
|
(unsigned long)( arg.AsTimeTagUnchecked() >> 32 );
|
||||||
break;
|
|
||||||
|
// strip trailing newline from string returned by ctime
|
||||||
case INT64_TYPE_TAG:
|
const char *timeString = std::ctime( &t );
|
||||||
os << "int64:" << arg.AsInt64Unchecked();
|
size_t len = strlen( timeString );
|
||||||
break;
|
char *s = new char[ len + 1 ];
|
||||||
|
strcpy( s, timeString );
|
||||||
case TIME_TAG_TYPE_TAG:
|
if( len )
|
||||||
{
|
s[ len - 1 ] = '\0';
|
||||||
os << "OSC-timetag:" << arg.AsTimeTagUnchecked() << " ";
|
|
||||||
|
os << " " << s;
|
||||||
std::time_t t =
|
}
|
||||||
(unsigned long)( arg.AsTimeTagUnchecked() >> 32 );
|
break;
|
||||||
|
|
||||||
const char *timeString = std::ctime( &t );
|
case DOUBLE_TYPE_TAG:
|
||||||
size_t len = std::strlen( timeString );
|
os << "double:" << arg.AsDoubleUnchecked();
|
||||||
|
break;
|
||||||
// -1 to omit trailing newline from string returned by ctime()
|
|
||||||
if( len > 1 )
|
case STRING_TYPE_TAG:
|
||||||
os.write( timeString, len - 1 );
|
os << "OSC-string:`" << arg.AsStringUnchecked() << "'";
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
case SYMBOL_TYPE_TAG:
|
||||||
case DOUBLE_TYPE_TAG:
|
os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'";
|
||||||
os << "double:" << arg.AsDoubleUnchecked();
|
break;
|
||||||
break;
|
|
||||||
|
case BLOB_TYPE_TAG:
|
||||||
case STRING_TYPE_TAG:
|
{
|
||||||
os << "OSC-string:`" << arg.AsStringUnchecked() << "'";
|
unsigned long size;
|
||||||
break;
|
const void *data;
|
||||||
|
arg.AsBlobUnchecked( data, size );
|
||||||
case SYMBOL_TYPE_TAG:
|
os << "OSC-blob:<<" << std::hex << std::setfill('0');
|
||||||
os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'";
|
unsigned char *p = (unsigned char*)data;
|
||||||
break;
|
for( unsigned long i = 0; i < size; ++i ){
|
||||||
|
os << "0x" << std::setw(2) << int(p[i]);
|
||||||
case BLOB_TYPE_TAG:
|
if( i != size-1 )
|
||||||
{
|
os << ' ';
|
||||||
const void *data;
|
}
|
||||||
osc_bundle_element_size_t size;
|
os.unsetf(std::ios::basefield);
|
||||||
arg.AsBlobUnchecked( data, size );
|
os << ">>" << std::setfill(' ');
|
||||||
os << "OSC-blob:<<" << std::hex << std::setfill('0');
|
}
|
||||||
unsigned char *p = (unsigned char*)data;
|
break;
|
||||||
for( osc_bundle_element_size_t i = 0; i < size; ++i ){
|
|
||||||
os << "0x" << std::setw(2) << int(p[i]);
|
default:
|
||||||
if( i != size-1 )
|
os << "unknown";
|
||||||
os << ' ';
|
}
|
||||||
}
|
|
||||||
os.unsetf(std::ios::basefield);
|
return os;
|
||||||
os << ">>" << std::setfill(' ');
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )
|
||||||
case ARRAY_BEGIN_TYPE_TAG:
|
{
|
||||||
os << "[";
|
|
||||||
break;
|
os << "[" << m.AddressPattern();
|
||||||
|
bool first = true;
|
||||||
case ARRAY_END_TYPE_TAG:
|
|
||||||
os << "]";
|
for( ReceivedMessage::const_iterator i = m.ArgumentsBegin();
|
||||||
break;
|
i != m.ArgumentsEnd(); ++i ){
|
||||||
|
if( first ){
|
||||||
default:
|
os << " ";
|
||||||
os << "unknown";
|
first = false;
|
||||||
}
|
}else{
|
||||||
|
os << ", ";
|
||||||
return os;
|
}
|
||||||
}
|
|
||||||
|
os << *i;
|
||||||
|
}
|
||||||
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )
|
|
||||||
{
|
os << "]";
|
||||||
os << "[";
|
|
||||||
if( m.AddressPatternIsUInt32() )
|
return os;
|
||||||
os << m.AddressPatternAsUInt32();
|
}
|
||||||
else
|
|
||||||
os << m.AddressPattern();
|
|
||||||
|
std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b )
|
||||||
bool first = true;
|
{
|
||||||
for( ReceivedMessage::const_iterator i = m.ArgumentsBegin();
|
static int indent = 0;
|
||||||
i != m.ArgumentsEnd(); ++i ){
|
|
||||||
if( first ){
|
for( int j=0; j < indent; ++j )
|
||||||
os << " ";
|
os << " ";
|
||||||
first = false;
|
os << "{ ( ";
|
||||||
}else{
|
if( b.TimeTag() == 1 )
|
||||||
os << ", ";
|
os << "immediate";
|
||||||
}
|
else
|
||||||
|
os << b.TimeTag();
|
||||||
os << *i;
|
os << " )\n";
|
||||||
}
|
|
||||||
|
++indent;
|
||||||
os << "]";
|
|
||||||
|
for( ReceivedBundle::const_iterator i = b.ElementsBegin();
|
||||||
return os;
|
i != b.ElementsEnd(); ++i ){
|
||||||
}
|
if( i->IsBundle() ){
|
||||||
|
ReceivedBundle b(*i);
|
||||||
|
os << b << "\n";
|
||||||
std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b )
|
}else{
|
||||||
{
|
ReceivedMessage m(*i);
|
||||||
static int indent = 0;
|
for( int j=0; j < indent; ++j )
|
||||||
|
os << " ";
|
||||||
for( int j=0; j < indent; ++j )
|
os << m << "\n";
|
||||||
os << " ";
|
}
|
||||||
os << "{ ( ";
|
}
|
||||||
if( b.TimeTag() == 1 )
|
|
||||||
os << "immediate";
|
--indent;
|
||||||
else
|
|
||||||
os << b.TimeTag();
|
for( int j=0; j < indent; ++j )
|
||||||
os << " )\n";
|
os << " ";
|
||||||
|
os << "}";
|
||||||
++indent;
|
|
||||||
|
return os;
|
||||||
for( ReceivedBundle::const_iterator i = b.ElementsBegin();
|
}
|
||||||
i != b.ElementsEnd(); ++i ){
|
|
||||||
if( i->IsBundle() ){
|
|
||||||
ReceivedBundle b(*i);
|
std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p )
|
||||||
os << b << "\n";
|
{
|
||||||
}else{
|
if( p.IsBundle() ){
|
||||||
ReceivedMessage m(*i);
|
ReceivedBundle b(p);
|
||||||
for( int j=0; j < indent; ++j )
|
os << b << "\n";
|
||||||
os << " ";
|
}else{
|
||||||
os << m << "\n";
|
ReceivedMessage m(p);
|
||||||
}
|
os << m << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
--indent;
|
return os;
|
||||||
|
}
|
||||||
for( int j=0; j < indent; ++j )
|
|
||||||
os << " ";
|
} // namespace osc
|
||||||
os << "}";
|
|
||||||
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p )
|
|
||||||
{
|
|
||||||
if( p.IsBundle() ){
|
|
||||||
ReceivedBundle b(p);
|
|
||||||
os << b << "\n";
|
|
||||||
}else{
|
|
||||||
ReceivedMessage m(p);
|
|
||||||
os << m << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace osc
|
|
||||||
@@ -1,54 +1,49 @@
|
|||||||
/*
|
/*
|
||||||
oscpack -- Open Sound Control (OSC) packet manipulation library
|
oscpack -- Open Sound Control packet manipulation library
|
||||||
http://www.rossbencina.com/code/oscpack
|
http://www.audiomulch.com/~rossb/oscpack
|
||||||
|
|
||||||
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
|
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files
|
a copy of this software and associated documentation files
|
||||||
(the "Software"), to deal in the Software without restriction,
|
(the "Software"), to deal in the Software without restriction,
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
including without limitation the rights to use, copy, modify, merge,
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
and to permit persons to whom the Software is furnished to do so,
|
||||||
subject to the following conditions:
|
subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
The above copyright notice and this permission notice shall be
|
||||||
included in all copies or substantial portions of the Software.
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Any person wishing to distribute modifications to the Software is
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
requested to send the modifications to the original developer so that
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
they can be incorporated into the canonical version.
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
*/
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
/*
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
The text above constitutes the entire oscpack license; however,
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
the oscpack developer(s) also make the following non-binding requests:
|
*/
|
||||||
|
#ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
|
||||||
Any person wishing to distribute modifications to the Software is
|
#define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
|
||||||
requested to send the modifications to the original developer so that
|
|
||||||
they can be incorporated into the canonical version. It is also
|
#include <iosfwd>
|
||||||
requested that these non-binding requests be included whenever the
|
|
||||||
above license is reproduced.
|
#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
|
||||||
*/
|
#include "OscReceivedElements.h"
|
||||||
#ifndef INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H
|
#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
|
||||||
#define INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H
|
|
||||||
|
|
||||||
#include <iosfwd>
|
namespace osc{
|
||||||
|
|
||||||
#include "OscReceivedElements.h"
|
std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p );
|
||||||
|
std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg );
|
||||||
|
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m );
|
||||||
namespace osc{
|
std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b );
|
||||||
|
|
||||||
std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p );
|
} // namespace osc
|
||||||
std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg );
|
|
||||||
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m );
|
#endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */
|
||||||
std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b );
|
|
||||||
|
|
||||||
} // namespace osc
|
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H */
|
|
||||||
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
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,52 +1,40 @@
|
|||||||
/*
|
/*
|
||||||
oscpack -- Open Sound Control (OSC) packet manipulation library
|
oscpack -- Open Sound Control packet manipulation library
|
||||||
http://www.rossbencina.com/code/oscpack
|
http://www.audiomulch.com/~rossb/oscpack
|
||||||
|
|
||||||
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
|
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files
|
a copy of this software and associated documentation files
|
||||||
(the "Software"), to deal in the Software without restriction,
|
(the "Software"), to deal in the Software without restriction,
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
including without limitation the rights to use, copy, modify, merge,
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
and to permit persons to whom the Software is furnished to do so,
|
||||||
subject to the following conditions:
|
subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
The above copyright notice and this permission notice shall be
|
||||||
included in all copies or substantial portions of the Software.
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Any person wishing to distribute modifications to the Software is
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
requested to send the modifications to the original developer so that
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
they can be incorporated into the canonical version.
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
*/
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
/*
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
The text above constitutes the entire oscpack license; however,
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
the oscpack developer(s) also make the following non-binding requests:
|
*/
|
||||||
|
#include "OscTypes.h"
|
||||||
Any person wishing to distribute modifications to the Software is
|
|
||||||
requested to send the modifications to the original developer so that
|
namespace osc{
|
||||||
they can be incorporated into the canonical version. It is also
|
|
||||||
requested that these non-binding requests be included whenever the
|
BundleInitiator BeginBundleImmediate(1);
|
||||||
above license is reproduced.
|
BundleTerminator EndBundle;
|
||||||
*/
|
MessageTerminator EndMessage;
|
||||||
#include "OscTypes.h"
|
NilType Nil;
|
||||||
|
InfinitumType Infinitum;
|
||||||
namespace osc{
|
|
||||||
|
} // namespace osc
|
||||||
BundleInitiator BeginBundleImmediate(1);
|
|
||||||
BundleTerminator EndBundle;
|
|
||||||
MessageTerminator EndMessage;
|
|
||||||
NilType OscNil;
|
|
||||||
#ifndef _OBJC_OBJC_H_
|
|
||||||
NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead
|
|
||||||
#endif
|
|
||||||
InfinitumType Infinitum;
|
|
||||||
ArrayInitiator BeginArray;
|
|
||||||
ArrayTerminator EndArray;
|
|
||||||
|
|
||||||
} // namespace osc
|
|
||||||
@@ -1,240 +1,178 @@
|
|||||||
/*
|
/*
|
||||||
oscpack -- Open Sound Control (OSC) packet manipulation library
|
oscpack -- Open Sound Control packet manipulation library
|
||||||
http://www.rossbencina.com/code/oscpack
|
http://www.audiomulch.com/~rossb/oscpack
|
||||||
|
|
||||||
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
|
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files
|
a copy of this software and associated documentation files
|
||||||
(the "Software"), to deal in the Software without restriction,
|
(the "Software"), to deal in the Software without restriction,
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
including without limitation the rights to use, copy, modify, merge,
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
and to permit persons to whom the Software is furnished to do so,
|
||||||
subject to the following conditions:
|
subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
The above copyright notice and this permission notice shall be
|
||||||
included in all copies or substantial portions of the Software.
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Any person wishing to distribute modifications to the Software is
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
requested to send the modifications to the original developer so that
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
they can be incorporated into the canonical version.
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
*/
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
/*
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
The text above constitutes the entire oscpack license; however,
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
the oscpack developer(s) also make the following non-binding requests:
|
*/
|
||||||
|
#ifndef INCLUDED_OSCTYPES_H
|
||||||
Any person wishing to distribute modifications to the Software is
|
#define INCLUDED_OSCTYPES_H
|
||||||
requested to send the modifications to the original developer so that
|
|
||||||
they can be incorporated into the canonical version. It is also
|
|
||||||
requested that these non-binding requests be included whenever the
|
namespace osc{
|
||||||
above license is reproduced.
|
|
||||||
*/
|
// basic types
|
||||||
#ifndef INCLUDED_OSCPACK_OSCTYPES_H
|
|
||||||
#define INCLUDED_OSCPACK_OSCTYPES_H
|
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||||
|
|
||||||
|
typedef __int64 int64;
|
||||||
namespace osc{
|
typedef unsigned __int64 uint64;
|
||||||
|
|
||||||
// basic types
|
#else
|
||||||
|
|
||||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
typedef long long int64;
|
||||||
|
typedef unsigned long long uint64;
|
||||||
typedef __int64 int64;
|
|
||||||
typedef unsigned __int64 uint64;
|
#endif
|
||||||
|
|
||||||
#elif defined(__x86_64__) || defined(_M_X64)
|
|
||||||
|
|
||||||
typedef long int64;
|
#ifdef x86_64
|
||||||
typedef unsigned long uint64;
|
|
||||||
|
typedef signed int int32;
|
||||||
#else
|
typedef unsigned int uint32;
|
||||||
|
|
||||||
typedef long long int64;
|
#else
|
||||||
typedef unsigned long long uint64;
|
|
||||||
|
typedef signed long int32;
|
||||||
#endif
|
typedef unsigned long uint32;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__x86_64__) || defined(_M_X64)
|
|
||||||
|
|
||||||
typedef signed int int32;
|
enum TypeTagValues {
|
||||||
typedef unsigned int uint32;
|
TRUE_TYPE_TAG = 'T',
|
||||||
|
FALSE_TYPE_TAG = 'F',
|
||||||
#else
|
NIL_TYPE_TAG = 'N',
|
||||||
|
INFINITUM_TYPE_TAG = 'I',
|
||||||
typedef signed long int32;
|
INT32_TYPE_TAG = 'i',
|
||||||
typedef unsigned long uint32;
|
FLOAT_TYPE_TAG = 'f',
|
||||||
|
CHAR_TYPE_TAG = 'c',
|
||||||
#endif
|
RGBA_COLOR_TYPE_TAG = 'r',
|
||||||
|
MIDI_MESSAGE_TYPE_TAG = 'm',
|
||||||
|
INT64_TYPE_TAG = 'h',
|
||||||
enum ValueTypeSizes{
|
TIME_TAG_TYPE_TAG = 't',
|
||||||
OSC_SIZEOF_INT32 = 4,
|
DOUBLE_TYPE_TAG = 'd',
|
||||||
OSC_SIZEOF_UINT32 = 4,
|
STRING_TYPE_TAG = 's',
|
||||||
OSC_SIZEOF_INT64 = 8,
|
SYMBOL_TYPE_TAG = 'S',
|
||||||
OSC_SIZEOF_UINT64 = 8,
|
BLOB_TYPE_TAG = 'b'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// osc_bundle_element_size_t is used for the size of bundle elements and blobs
|
|
||||||
// the OSC spec specifies these as int32 (signed) but we ensure that they
|
// i/o manipulators used for streaming interfaces
|
||||||
// are always positive since negative field sizes make no sense.
|
|
||||||
|
struct BundleInitiator{
|
||||||
typedef int32 osc_bundle_element_size_t;
|
explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {}
|
||||||
|
uint64 timeTag;
|
||||||
enum {
|
};
|
||||||
OSC_INT32_MAX = 0x7FFFFFFF,
|
|
||||||
|
extern BundleInitiator BeginBundleImmediate;
|
||||||
// Element sizes are specified to be int32, and are always rounded up to nearest
|
|
||||||
// multiple of 4. Therefore their values can't be greater than 0x7FFFFFFC.
|
inline BundleInitiator BeginBundle( uint64 timeTag=1 )
|
||||||
OSC_BUNDLE_ELEMENT_SIZE_MAX = 0x7FFFFFFC
|
{
|
||||||
};
|
return BundleInitiator(timeTag);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool IsValidElementSizeValue( osc_bundle_element_size_t x )
|
|
||||||
{
|
struct BundleTerminator{
|
||||||
// sizes may not be negative or exceed OSC_BUNDLE_ELEMENT_SIZE_MAX
|
};
|
||||||
return x >= 0 && x <= OSC_BUNDLE_ELEMENT_SIZE_MAX;
|
|
||||||
}
|
extern BundleTerminator EndBundle;
|
||||||
|
|
||||||
|
struct BeginMessage{
|
||||||
inline bool IsMultipleOf4( osc_bundle_element_size_t x )
|
explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {}
|
||||||
{
|
const char *addressPattern;
|
||||||
return (x & ((osc_bundle_element_size_t)0x03)) == 0;
|
};
|
||||||
}
|
|
||||||
|
struct MessageTerminator{
|
||||||
|
};
|
||||||
enum TypeTagValues {
|
|
||||||
TRUE_TYPE_TAG = 'T',
|
extern MessageTerminator EndMessage;
|
||||||
FALSE_TYPE_TAG = 'F',
|
|
||||||
NIL_TYPE_TAG = 'N',
|
|
||||||
INFINITUM_TYPE_TAG = 'I',
|
// osc specific types. they are defined as structs so they can be used
|
||||||
INT32_TYPE_TAG = 'i',
|
// as separately identifiable types with the streaming operators.
|
||||||
FLOAT_TYPE_TAG = 'f',
|
|
||||||
CHAR_TYPE_TAG = 'c',
|
struct NilType{
|
||||||
RGBA_COLOR_TYPE_TAG = 'r',
|
};
|
||||||
MIDI_MESSAGE_TYPE_TAG = 'm',
|
|
||||||
INT64_TYPE_TAG = 'h',
|
extern NilType Nil;
|
||||||
TIME_TAG_TYPE_TAG = 't',
|
|
||||||
DOUBLE_TYPE_TAG = 'd',
|
|
||||||
STRING_TYPE_TAG = 's',
|
struct InfinitumType{
|
||||||
SYMBOL_TYPE_TAG = 'S',
|
};
|
||||||
BLOB_TYPE_TAG = 'b',
|
|
||||||
ARRAY_BEGIN_TYPE_TAG = '[',
|
extern InfinitumType Infinitum;
|
||||||
ARRAY_END_TYPE_TAG = ']'
|
|
||||||
};
|
struct RgbaColor{
|
||||||
|
RgbaColor() {}
|
||||||
|
explicit RgbaColor( uint32 value_ ) : value( value_ ) {}
|
||||||
|
uint32 value;
|
||||||
// i/o manipulators used for streaming interfaces
|
|
||||||
|
operator uint32() const { return value; }
|
||||||
struct BundleInitiator{
|
};
|
||||||
explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {}
|
|
||||||
uint64 timeTag;
|
|
||||||
};
|
struct MidiMessage{
|
||||||
|
MidiMessage() {}
|
||||||
extern BundleInitiator BeginBundleImmediate;
|
explicit MidiMessage( uint32 value_ ) : value( value_ ) {}
|
||||||
|
uint32 value;
|
||||||
inline BundleInitiator BeginBundle( uint64 timeTag=1 )
|
|
||||||
{
|
operator uint32() const { return value; }
|
||||||
return BundleInitiator(timeTag);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
struct TimeTag{
|
||||||
struct BundleTerminator{
|
TimeTag() {}
|
||||||
};
|
explicit TimeTag( uint64 value_ ) : value( value_ ) {}
|
||||||
|
uint64 value;
|
||||||
extern BundleTerminator EndBundle;
|
|
||||||
|
operator uint64() const { return value; }
|
||||||
struct BeginMessage{
|
};
|
||||||
explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {}
|
|
||||||
const char *addressPattern;
|
|
||||||
};
|
struct Symbol{
|
||||||
|
Symbol() {}
|
||||||
struct MessageTerminator{
|
explicit Symbol( const char* value_ ) : value( value_ ) {}
|
||||||
};
|
const char* value;
|
||||||
|
|
||||||
extern MessageTerminator EndMessage;
|
operator const char *() const { return value; }
|
||||||
|
};
|
||||||
|
|
||||||
// osc specific types. they are defined as structs so they can be used
|
|
||||||
// as separately identifiable types with the streaming operators.
|
struct Blob{
|
||||||
|
Blob() {}
|
||||||
struct NilType{
|
explicit Blob( const void* data_, unsigned long size_ )
|
||||||
};
|
: data( data_ ), size( size_ ) {}
|
||||||
|
const void* data;
|
||||||
extern NilType OscNil;
|
unsigned long size;
|
||||||
|
};
|
||||||
#ifndef _OBJC_OBJC_H_
|
|
||||||
extern NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead
|
} // namespace osc
|
||||||
#endif
|
|
||||||
|
|
||||||
struct InfinitumType{
|
#endif /* INCLUDED_OSCTYPES_H */
|
||||||
};
|
|
||||||
|
|
||||||
extern InfinitumType Infinitum;
|
|
||||||
|
|
||||||
struct RgbaColor{
|
|
||||||
RgbaColor() {}
|
|
||||||
explicit RgbaColor( uint32 value_ ) : value( value_ ) {}
|
|
||||||
uint32 value;
|
|
||||||
|
|
||||||
operator uint32() const { return value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct MidiMessage{
|
|
||||||
MidiMessage() {}
|
|
||||||
explicit MidiMessage( uint32 value_ ) : value( value_ ) {}
|
|
||||||
uint32 value;
|
|
||||||
|
|
||||||
operator uint32() const { return value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct TimeTag{
|
|
||||||
TimeTag() {}
|
|
||||||
explicit TimeTag( uint64 value_ ) : value( value_ ) {}
|
|
||||||
uint64 value;
|
|
||||||
|
|
||||||
operator uint64() const { return value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Symbol{
|
|
||||||
Symbol() {}
|
|
||||||
explicit Symbol( const char* value_ ) : value( value_ ) {}
|
|
||||||
const char* value;
|
|
||||||
|
|
||||||
operator const char *() const { return value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Blob{
|
|
||||||
Blob() {}
|
|
||||||
explicit Blob( const void* data_, osc_bundle_element_size_t size_ )
|
|
||||||
: data( data_ ), size( size_ ) {}
|
|
||||||
const void* data;
|
|
||||||
osc_bundle_element_size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ArrayInitiator{
|
|
||||||
};
|
|
||||||
|
|
||||||
extern ArrayInitiator BeginArray;
|
|
||||||
|
|
||||||
struct ArrayTerminator{
|
|
||||||
};
|
|
||||||
|
|
||||||
extern ArrayTerminator EndArray;
|
|
||||||
|
|
||||||
} // namespace osc
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* INCLUDED_OSCPACK_OSCTYPES_H */
|
|
||||||
Reference in New Issue
Block a user