From 8299e4db22ea145a059727ae954d632a3ad35c09 Mon Sep 17 00:00:00 2001 From: Malin E Date: Tue, 30 Nov 2021 10:46:44 +0100 Subject: [PATCH 1/7] Address PR comments --- .../interaction/joystickcamerastates.h | 26 ++++--- .../openspace/navigation/navigationhandler.h | 6 +- src/interaction/joystickcamerastates.cpp | 73 +++++++++---------- src/interaction/joystickinputstate.cpp | 6 +- src/navigation/navigationhandler.cpp | 12 +-- src/navigation/navigationhandler_lua.inl | 6 +- 6 files changed, 67 insertions(+), 62 deletions(-) diff --git a/include/openspace/interaction/joystickcamerastates.h b/include/openspace/interaction/joystickcamerastates.h index d0b2d74039..2c96b58a5c 100644 --- a/include/openspace/interaction/joystickcamerastates.h +++ b/include/openspace/interaction/joystickcamerastates.h @@ -54,7 +54,7 @@ public: }; enum class JoystickType { - JoystickLike = 0, + JoystickLike, TriggerLike }; @@ -88,14 +88,14 @@ public: void updateStateFromInput( const JoystickInputStates& joystickInputStates, double deltaTime); - void setAxisMapping(const std::string& joystickName, int axis, AxisType mapping, + void setAxisMapping(std::string joystickName, int axis, AxisType mapping, AxisInvert shouldInvert = AxisInvert::No, JoystickType joystickType = JoystickType::JoystickLike, bool isSticky = false, double sensitivity = 0.0 ); - void setAxisMappingProperty(const std::string& joystickName, int axis, - const std::string& propertyUri, float min = 0.f, float max = 1.f, + void setAxisMappingProperty(std::string joystickName, int axis, + std::string propertyUri, float min = 0.f, float max = 1.f, AxisInvert shouldInvert = AxisInvert::No, bool isRemote = true ); @@ -119,7 +119,6 @@ private: // be accessed much more often and thus have to be more efficient. And storing a few // extra AxisInformation that are not used will not matter that much; finding an axis // location in a potential map each frame, however, would - std::array axisMapping; // This array is used to store the old axis values from the previous frame, @@ -127,9 +126,16 @@ private: std::array prevAxisValues; struct ButtonInformation { + // The script that is run when the button is activated std::string command; + + // When is the button considered activated JoystickAction action; + + // If the script should be syncronised to other remote sessions or not ButtonCommandRemote synchronization; + + // Short documentation on what the script of this button does std::string documentation; }; @@ -140,8 +146,8 @@ private: // Find the item in _joystickCameraStates that corresponds to the given joystickName // return a pointer to the item, if not found then return nullptr - JoystickCameraState* getJoystickCameraState(const std::string& joystickName); - const JoystickCameraState* getJoystickCameraState(const std::string& joystickName) const; + JoystickCameraState* joystickCameraState(const std::string& joystickName); + const JoystickCameraState* joystickCameraState(const std::string& joystickName) const; // Ues getJoystickCameraState(name) to find the joystickCameraState that // corresponds to the given joystickName. If not found then add a new item if possible @@ -204,9 +210,9 @@ inline std::string to_string( { using T = openspace::interaction::JoystickCameraStates::JoystickType; switch (value) { - case T::JoystickLike: return "JoystickLike"; - case T::TriggerLike: return "TriggerLike"; - default: return ""; + case T::JoystickLike: return "JoystickLike"; + case T::TriggerLike: return "TriggerLike"; + default: return ""; } } diff --git a/include/openspace/navigation/navigationhandler.h b/include/openspace/navigation/navigationhandler.h index 3a6bbeac36..f66e765ac5 100644 --- a/include/openspace/navigation/navigationhandler.h +++ b/include/openspace/navigation/navigationhandler.h @@ -98,7 +98,7 @@ public: void mousePositionCallback(double x, double y); void mouseScrollWheelCallback(double pos); - void setJoystickAxisMapping(const std::string& joystickName, + void setJoystickAxisMapping(std::string joystickName, int axis, JoystickCameraStates::AxisType mapping, JoystickCameraStates::AxisInvert shouldInvert = JoystickCameraStates::AxisInvert::No, @@ -107,8 +107,8 @@ public: bool isSticky = false, double sensitivity = 0.0 ); - void setJoystickAxisMappingProperty(const std::string& joystickName, - int axis, const std::string& propertyUri, + void setJoystickAxisMappingProperty(std::string joystickName, + int axis, std::string propertyUri, float min = 0.f, float max = 1.f, JoystickCameraStates::AxisInvert shouldInvert = JoystickCameraStates::AxisInvert::No, bool isRemote = true diff --git a/src/interaction/joystickcamerastates.cpp b/src/interaction/joystickcamerastates.cpp index 9d4b5ea4df..22a9c6f53e 100644 --- a/src/interaction/joystickcamerastates.cpp +++ b/src/interaction/joystickcamerastates.cpp @@ -56,15 +56,14 @@ void JoystickCameraStates::updateStateFromInput( continue; } - JoystickCameraState* joystickCameraState = - getJoystickCameraState(joystickInputState.name); + JoystickCameraState* joystick = joystickCameraState(joystickInputState.name); - if (!joystickCameraState) { + if (!joystick) { continue; } for (int i = 0; i < JoystickInputState::MaxAxes; ++i) { - AxisInformation t = joystickCameraState->axisMapping[i]; + AxisInformation t = joystick->axisMapping[i]; if (t.type == AxisType::None) { continue; } @@ -73,13 +72,13 @@ void JoystickCameraStates::updateStateFromInput( float value = rawValue; if (t.isSticky) { - value = rawValue - joystickCameraState->prevAxisValues[i]; - joystickCameraState->prevAxisValues[i] = rawValue; + value = rawValue - joystick->prevAxisValues[i]; + joystick->prevAxisValues[i] = rawValue; } if ((t.joystickType == JoystickType::JoystickLike && - std::fabs(value) <= t.deadzone) || - (t.joystickType == JoystickType::TriggerLike && value <= -1 + t.deadzone)) + std::abs(value) <= t.deadzone) || + (t.joystickType == JoystickType::TriggerLike && value <= -1.f + t.deadzone)) { continue; } @@ -151,8 +150,8 @@ void JoystickCameraStates::updateStateFromInput( localRotation.second.y += value; break; case AxisType::Property: - std::string script = "openspace.setPropertyValue(\"" + - t.propertyUri + "\", " + std::to_string(value) + ");"; + std::string script = fmt::format("openspace.setPropertyValue('{}', {});", + t.propertyUri, value); global::scriptEngine->queueScript( script, @@ -163,7 +162,7 @@ void JoystickCameraStates::updateStateFromInput( } for (int i = 0; i < JoystickInputState::MaxButtons; ++i) { - auto itRange = joystickCameraState->buttonMapping.equal_range(i); + auto itRange = joystick->buttonMapping.equal_range(i); for (auto it = itRange.first; it != itRange.second; ++it) { bool active = global::joystickInputStates->button( joystickInputState.name, @@ -217,7 +216,7 @@ void JoystickCameraStates::updateStateFromInput( } } -void JoystickCameraStates::setAxisMapping(const std::string& joystickName, +void JoystickCameraStates::setAxisMapping(std::string joystickName, int axis, AxisType mapping, AxisInvert shouldInvert, JoystickType joystickType, @@ -241,9 +240,9 @@ void JoystickCameraStates::setAxisMapping(const std::string& joystickName, global::joystickInputStates->axis(joystickName, axis); } -void JoystickCameraStates::setAxisMappingProperty(const std::string& joystickName, +void JoystickCameraStates::setAxisMappingProperty(std::string joystickName, int axis, - const std::string& propertyUri, + std::string propertyUri, float min, float max, AxisInvert shouldInvert, bool isRemote) @@ -270,13 +269,13 @@ JoystickCameraStates::AxisInformation JoystickCameraStates::axisMapping( const std::string& joystickName, int axis) const { - const JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); - if (!joystickCameraState) { + const JoystickCameraState* joystick = joystickCameraState(joystickName); + if (!joystick) { JoystickCameraStates::AxisInformation dummy; return dummy; } - return joystickCameraState->axisMapping[axis]; + return joystick->axisMapping[axis]; } void JoystickCameraStates::setDeadzone(const std::string& joystickName, int axis, @@ -291,12 +290,12 @@ void JoystickCameraStates::setDeadzone(const std::string& joystickName, int axis } float JoystickCameraStates::deadzone(const std::string& joystickName, int axis) const { - const JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); - if (!joystickCameraState) { - return 0.0f; + const JoystickCameraState* joystick = joystickCameraState(joystickName); + if (!joystick) { + return 0.f; } - return joystickCameraState->axisMapping[axis].deadzone; + return joystick->axisMapping[axis].deadzone; } void JoystickCameraStates::bindButtonCommand(const std::string& joystickName, @@ -319,18 +318,18 @@ void JoystickCameraStates::bindButtonCommand(const std::string& joystickName, void JoystickCameraStates::clearButtonCommand(const std::string& joystickName, int button) { - JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); - if (!joystickCameraState) { + JoystickCameraState* joystick = joystickCameraState(joystickName); + if (!joystick) { return; } - for (auto it = joystickCameraState->buttonMapping.begin(); - it != joystickCameraState->buttonMapping.end(); ) + for (auto it = joystick->buttonMapping.begin(); + it != joystick->buttonMapping.end(); ) { // If the current iterator is the button that we are looking for, delete it // (std::multimap::erase will return the iterator to the next element for us) if (it->first == button) { - it = joystickCameraState->buttonMapping.erase(it); + it = joystick->buttonMapping.erase(it); } else { ++it; @@ -343,19 +342,19 @@ std::vector JoystickCameraStates::buttonCommand( int button) const { std::vector result; - const JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); - if (!joystickCameraState) { + const JoystickCameraState* joystick = joystickCameraState(joystickName); + if (!joystick) { return result; } - auto itRange = joystickCameraState->buttonMapping.equal_range(button); + auto itRange = joystick->buttonMapping.equal_range(button); for (auto it = itRange.first; it != itRange.second; ++it) { result.push_back(it->second.command); } return result; } -JoystickCameraStates::JoystickCameraState* JoystickCameraStates::getJoystickCameraState( +JoystickCameraStates::JoystickCameraState* JoystickCameraStates::joystickCameraState( const std::string& joystickName) { for (JoystickCameraState& joystickCameraState : _joystickCameraStates) { @@ -368,7 +367,7 @@ JoystickCameraStates::JoystickCameraState* JoystickCameraStates::getJoystickCame } const JoystickCameraStates::JoystickCameraState* - JoystickCameraStates::getJoystickCameraState(const std::string& joystickName) const +JoystickCameraStates::joystickCameraState(const std::string& joystickName) const { for (const JoystickCameraState& joystickCameraState : _joystickCameraStates) { if (joystickCameraState.joystickName == joystickName) { @@ -381,14 +380,14 @@ const JoystickCameraStates::JoystickCameraState* } JoystickCameraStates::JoystickCameraState* - JoystickCameraStates::findOrAddJoystickCameraState(const std::string& joystickName) +JoystickCameraStates::findOrAddJoystickCameraState(const std::string& joystickName) { - JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); - if (!joystickCameraState) { + JoystickCameraState* joystick = joystickCameraState(joystickName); + if (!joystick) { if (_joystickCameraStates.size() < JoystickInputStates::MaxNumJoysticks) { _joystickCameraStates.push_back(JoystickCameraState()); - joystickCameraState = &_joystickCameraStates.back(); - joystickCameraState->joystickName = joystickName; + joystick = &_joystickCameraStates.back(); + joystick->joystickName = joystickName; } else { LWARNING(fmt::format("Cannot add more joysticks, only {} joysticks are " @@ -396,7 +395,7 @@ JoystickCameraStates::JoystickCameraState* return nullptr; } } - return joystickCameraState; + return joystick; } diff --git a/src/interaction/joystickinputstate.cpp b/src/interaction/joystickinputstate.cpp index 9c0da27225..170a40e296 100644 --- a/src/interaction/joystickinputstate.cpp +++ b/src/interaction/joystickinputstate.cpp @@ -36,7 +36,7 @@ namespace openspace::interaction { float JoystickInputStates::axis(const std::string& joystickName, int axis) const { ghoul_precondition(axis >= 0, "axis must be 0 or positive"); - if(joystickName.empty()) { + if (joystickName.empty()) { float res = std::accumulate( begin(), end(), @@ -63,7 +63,7 @@ float JoystickInputStates::axis(const std::string& joystickName, int axis) const } if (!state) { - return 0.0f; + return 0.f; } return state->axes[axis]; @@ -72,7 +72,7 @@ float JoystickInputStates::axis(const std::string& joystickName, int axis) const bool JoystickInputStates::button(const std::string& joystickName, int button, JoystickAction action) const { ghoul_precondition(button >= 0, "button must be 0 or positive"); - if(joystickName.empty()) { + if (joystickName.empty()) { bool res = std::any_of( begin(), end(), diff --git a/src/navigation/navigationhandler.cpp b/src/navigation/navigationhandler.cpp index 439bcd503e..7f5ae8854e 100644 --- a/src/navigation/navigationhandler.cpp +++ b/src/navigation/navigationhandler.cpp @@ -498,7 +498,7 @@ void NavigationHandler::loadNavigationState(const std::string& filepath) { } } -void NavigationHandler::setJoystickAxisMapping(const std::string& joystickName, int axis, +void NavigationHandler::setJoystickAxisMapping(std::string joystickName, int axis, JoystickCameraStates::AxisType mapping, JoystickCameraStates::AxisInvert shouldInvert, JoystickCameraStates::JoystickType joystickType, @@ -506,7 +506,7 @@ void NavigationHandler::setJoystickAxisMapping(const std::string& joystickName, double sensitivity) { _orbitalNavigator.joystickStates().setAxisMapping( - joystickName, + std::move(joystickName), axis, mapping, shouldInvert, @@ -516,17 +516,17 @@ void NavigationHandler::setJoystickAxisMapping(const std::string& joystickName, ); } -void NavigationHandler::setJoystickAxisMappingProperty(const std::string& joystickName, +void NavigationHandler::setJoystickAxisMappingProperty(std::string joystickName, int axis, - const std::string& propertyUri, + std::string propertyUri, float min, float max, JoystickCameraStates::AxisInvert shouldInvert, bool isRemote) { _orbitalNavigator.joystickStates().setAxisMappingProperty( - joystickName, + std::move(joystickName), axis, - propertyUri, + std::move(propertyUri), min, max, shouldInvert, diff --git a/src/navigation/navigationhandler_lua.inl b/src/navigation/navigationhandler_lua.inl index 9be6957ce2..0b7faca565 100644 --- a/src/navigation/navigationhandler_lua.inl +++ b/src/navigation/navigationhandler_lua.inl @@ -164,7 +164,7 @@ int bindJoystickAxis(lua_State* L) { joystickType = joystickType.value_or("JoystickLike"); global::navigationHandler->setJoystickAxisMapping( - joystickName, + std::move(joystickName), axis, ghoul::from_string(axisType), interaction::JoystickCameraStates::AxisInvert(*shouldInvert), @@ -188,9 +188,9 @@ int bindJoystickAxisProperty(lua_State* L) { isRemote = isRemote.value_or(true); global::navigationHandler->setJoystickAxisMappingProperty( - joystickName, + std::move(joystickName), axis, - propertyUri, + std::move(propertyUri), *min, *max, interaction::JoystickCameraStates::AxisInvert(*shouldInvert), From cc0a7b05cec66a32b53c1aaf48b46e6f1bc1fa30 Mon Sep 17 00:00:00 2001 From: Malin E Date: Tue, 30 Nov 2021 12:11:08 +0100 Subject: [PATCH 2/7] Add example asset for binding property to joystick --- data/assets/examples/joystickProperty.asset | 84 +++++++++++++++++++++ src/navigation/navigationhandler_lua.inl | 2 +- 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 data/assets/examples/joystickProperty.asset diff --git a/data/assets/examples/joystickProperty.asset b/data/assets/examples/joystickProperty.asset new file mode 100644 index 0000000000..a3a7ad6a12 --- /dev/null +++ b/data/assets/examples/joystickProperty.asset @@ -0,0 +1,84 @@ +-- Allowed values for the third parameter of bindJoystickAxis: +-- "None" +-- "Orbit X" +-- "Orbit Y" +-- "Zoom" -- both in and out +-- "Zoom In" +-- "Zoom Out" +-- "LocalRoll X" +-- "LocalRoll Y" +-- "GlobalRoll X" +-- "GlobalRoll Y" +-- "Pan X" +-- "Pan Y" +-- Fourth parameter determines whether the axis should be inverted +-- Fifth parameter determines whether the axis behaves like a joystick or a Trigger. +-- Allowed values are "JoystickLike" and "TriggerLike", the first one is the default +-- Sixth parameters determins if the axis should be "Sticky" or not. +-- The axis values can either go back to 0 when the joystick is released or it can +-- stay at the value it was before the joystick was released. +-- The latter is called a sticky axis, when the values don't go back to 0. +-- Seventh parameter is the sensitivity for the axis + + +-- Parameters for bindJoystickAxisProperty: +-- First - Name of the joystick that should be bound +-- Second - Which axis should be bound of this joystick +-- Third - The property uri +-- Fourth - (optional) The smallest value that you wnat to allow this property on the joystick +-- Fifth - (optional) The largest value that you wnat to allow this property on the joystick +-- Sixth - (optional) Determines whether the axis should be inverted +-- Seventh - (optional) Should this property change be sent to other connected remote sessions + +local XBoxController = { + LeftThumbStick = { 0 , 1 }, + RightThumbStick = { 2, 3 }, + LeftTrigger = 4, + RightTrigger = 5, + A = 0, + B = 1, + X = 2, + Y = 3, + LB = 4, + RB = 5, + Select = 6, + Start = 7, + LeftStickButton = 8, + RightStickButton = 9, + DPad = { + Up = 10, + Right = 11, + Down = 12, + Left = 13 + } +} + +isPropertyBound = true; + +local freezeValue = function(name, axis, min, max) + return [[ + if isPropertyBound then + openspace.navigation.bindJoystickAxis(']] .. name .. "', " .. axis .. [[, "None"); + isPropertyBound = false; + else + openspace.navigation.bindJoystickAxisProperty(']] .. name .. "', " .. axis .. [[, 'Scene.Earth.Scale.Scale', ]] .. min ..", " .. max.. [[); + isPropertyBound = true; + end + ]] +end + +asset.onInitialize(function() + local controller = XBoxController; + local name = "Xbox Controller"; + + -- Bind Right trigger to Earth Scale + openspace.navigation.bindJoystickAxisProperty(name, controller.RightTrigger, "Scene.Earth.Scale.Scale", 0.1, 100); + + -- Bind 'A' button to freeze current value + openspace.navigation.bindJoystickButton( + name, + controller.A, + freezeValue(name, controller.RightTrigger, 0.1, 100), + "Freeze current scale for Earth. Or release it to the trigger again." + ) +end) diff --git a/src/navigation/navigationhandler_lua.inl b/src/navigation/navigationhandler_lua.inl index 0b7faca565..85a9034d78 100644 --- a/src/navigation/navigationhandler_lua.inl +++ b/src/navigation/navigationhandler_lua.inl @@ -176,7 +176,7 @@ int bindJoystickAxis(lua_State* L) { } int bindJoystickAxisProperty(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 3, 9 }, "lua::bindJoystickAxisProperty"); + ghoul::lua::checkArgumentsAndThrow(L, { 3, 7 }, "lua::bindJoystickAxisProperty"); auto [joystickName, axis, propertyUri, min, max, shouldInvert, isRemote] = ghoul::lua::values< std::string, int, std::string, std::optional, std::optional, From 8766ba1242b00bf255b34224325cf8fa240db453 Mon Sep 17 00:00:00 2001 From: Malin E Date: Tue, 30 Nov 2021 17:22:46 +0100 Subject: [PATCH 3/7] Remove local variable in example --- data/assets/examples/joystickProperty.asset | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/data/assets/examples/joystickProperty.asset b/data/assets/examples/joystickProperty.asset index a3a7ad6a12..a5aedceace 100644 --- a/data/assets/examples/joystickProperty.asset +++ b/data/assets/examples/joystickProperty.asset @@ -53,10 +53,16 @@ local XBoxController = { } } -isPropertyBound = true; - local freezeValue = function(name, axis, min, max) return [[ + local joystickType = openspace.navigation.joystickAxis(']] .. name .. "', " .. axis .. [[); + local isPropertyBound = true; + if joystickType == "None" then + isPropertyBound = false; + else + isPropertyBound = true; + end + if isPropertyBound then openspace.navigation.bindJoystickAxis(']] .. name .. "', " .. axis .. [[, "None"); isPropertyBound = false; From 332850999ade212b3ee093a88308f9d550121d4a Mon Sep 17 00:00:00 2001 From: Malin E Date: Mon, 6 Dec 2021 15:59:39 +0100 Subject: [PATCH 4/7] Add osc files --- ext/osc/CMakeLists.txt | 53 ++ ext/osc/LICENSE | 34 + ext/osc/ip/IpEndpointName.cpp | 88 ++ ext/osc/ip/IpEndpointName.h | 83 ++ ext/osc/ip/NetworkingUtils.h | 56 ++ ext/osc/ip/PacketListener.h | 50 ++ ext/osc/ip/TimerListener.h | 47 ++ ext/osc/ip/UdpSocket.h | 177 ++++ ext/osc/ip/posix/NetworkingUtils.cpp | 64 ++ ext/osc/ip/posix/UdpSocket.cpp | 605 +++++++++++++ ext/osc/ip/win32/NetworkingUtils.cpp | 95 +++ ext/osc/ip/win32/UdpSocket.cpp | 574 +++++++++++++ ext/osc/osc/MessageMappingOscPacketListener.h | 80 ++ ext/osc/osc/OscException.h | 62 ++ ext/osc/osc/OscHostEndianness.h | 127 +++ ext/osc/osc/OscOutboundPacketStream.cpp | 683 +++++++++++++++ ext/osc/osc/OscOutboundPacketStream.h | 155 ++++ ext/osc/osc/OscPacketListener.h | 79 ++ ext/osc/osc/OscPrintReceivedElements.cpp | 261 ++++++ ext/osc/osc/OscPrintReceivedElements.h | 54 ++ ext/osc/osc/OscReceivedElements.cpp | 796 ++++++++++++++++++ ext/osc/osc/OscReceivedElements.h | 548 ++++++++++++ ext/osc/osc/OscTypes.cpp | 52 ++ ext/osc/osc/OscTypes.h | 240 ++++++ 24 files changed, 5063 insertions(+) create mode 100644 ext/osc/CMakeLists.txt create mode 100644 ext/osc/LICENSE create mode 100644 ext/osc/ip/IpEndpointName.cpp create mode 100644 ext/osc/ip/IpEndpointName.h create mode 100644 ext/osc/ip/NetworkingUtils.h create mode 100644 ext/osc/ip/PacketListener.h create mode 100644 ext/osc/ip/TimerListener.h create mode 100644 ext/osc/ip/UdpSocket.h create mode 100644 ext/osc/ip/posix/NetworkingUtils.cpp create mode 100644 ext/osc/ip/posix/UdpSocket.cpp create mode 100644 ext/osc/ip/win32/NetworkingUtils.cpp create mode 100644 ext/osc/ip/win32/UdpSocket.cpp create mode 100644 ext/osc/osc/MessageMappingOscPacketListener.h create mode 100644 ext/osc/osc/OscException.h create mode 100644 ext/osc/osc/OscHostEndianness.h create mode 100644 ext/osc/osc/OscOutboundPacketStream.cpp create mode 100644 ext/osc/osc/OscOutboundPacketStream.h create mode 100644 ext/osc/osc/OscPacketListener.h create mode 100644 ext/osc/osc/OscPrintReceivedElements.cpp create mode 100644 ext/osc/osc/OscPrintReceivedElements.h create mode 100644 ext/osc/osc/OscReceivedElements.cpp create mode 100644 ext/osc/osc/OscReceivedElements.h create mode 100644 ext/osc/osc/OscTypes.cpp create mode 100644 ext/osc/osc/OscTypes.h diff --git a/ext/osc/CMakeLists.txt b/ext/osc/CMakeLists.txt new file mode 100644 index 0000000000..27c30e8a18 --- /dev/null +++ b/ext/osc/CMakeLists.txt @@ -0,0 +1,53 @@ +cmake_minimum_required(VERSION 2.6) +PROJECT(Oscpack) +message(STATUS "Generating oscpack project") + +# separate versions of NetworkingUtils.cpp and UdpSocket.cpp are provided for Win32 and POSIX +# the IpSystemTypePath selects the correct ones based on the current platform + +IF(WIN32) + set(IpSystemTypePath ip/win32) +ELSE(WIN32) + set(IpSystemTypePath ip/posix) +ENDIF(WIN32) + +ADD_LIBRARY(oscpack + ip/IpEndpointName.h + ip/IpEndpointName.cpp + ip/NetworkingUtils.h + ${IpSystemTypePath}/NetworkingUtils.cpp + ip/UdpSocket.h + ${IpSystemTypePath}/UdpSocket.cpp + ip/PacketListener.h + ip/TimerListener.h + osc/OscTypes.h + osc/OscTypes.cpp + osc/OscHostEndianness.h + osc/OscException.h + osc/OscPacketListener.h + osc/MessageMappingOscPacketListener.h + osc/OscReceivedElements.h + osc/OscReceivedElements.cpp + osc/OscPrintReceivedElements.h + osc/OscPrintReceivedElements.cpp + osc/OscOutboundPacketStream.h + osc/OscOutboundPacketStream.cpp +) + +TARGET_INCLUDE_DIRECTORIES(oscpack PUBLIC ${CMAKE_SOURCE_DIR}) + +IF(WIN32) + target_link_libraries(oscpack PUBLIC Ws2_32 winmm) +ENDIF(WIN32) + +if(MSVC) + # Force to always compile with W4 + if(CMAKE_CXX_FLAGS MATCHES /W[0-4]) + string(REGEX REPLACE /W[0-4] /W4 CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) + else() + set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} /W4) + endif() +elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + # Update if necessary + set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-long-long -pedantic) +endif() diff --git a/ext/osc/LICENSE b/ext/osc/LICENSE new file mode 100644 index 0000000000..ebaaac1977 --- /dev/null +++ b/ext/osc/LICENSE @@ -0,0 +1,34 @@ +oscpack -- Open Sound Control (OSC) packet manipulation library +http://www.rossbencina.com/code/oscpack + +Copyright (c) 2004-2013 Ross Bencina + +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. \ No newline at end of file diff --git a/ext/osc/ip/IpEndpointName.cpp b/ext/osc/ip/IpEndpointName.cpp new file mode 100644 index 0000000000..50b0262216 --- /dev/null +++ b/ext/osc/ip/IpEndpointName.cpp @@ -0,0 +1,88 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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 "IpEndpointName.h" + +#include + +#include "NetworkingUtils.h" + + +unsigned long IpEndpointName::GetHostByName( const char *s ) +{ + return ::GetHostByName(s); +} + + +void IpEndpointName::AddressAsString( char *s ) const +{ + if( address == ANY_ADDRESS ){ + std::sprintf( s, "" ); + }else{ + std::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 ){ + std::sprintf( s, ":" ); + }else{ + std::sprintf( s, "%d.%d.%d.%d:", + (int)((address >> 24) & 0xFF), + (int)((address >> 16) & 0xFF), + (int)((address >> 8) & 0xFF), + (int)(address & 0xFF) ); + } + }else{ + if( address == ANY_ADDRESS ){ + std::sprintf( s, ":%d", port ); + }else{ + std::sprintf( s, "%d.%d.%d.%d:%d", + (int)((address >> 24) & 0xFF), + (int)((address >> 16) & 0xFF), + (int)((address >> 8) & 0xFF), + (int)(address & 0xFF), + (int)port ); + } + } +} diff --git a/ext/osc/ip/IpEndpointName.h b/ext/osc/ip/IpEndpointName.h new file mode 100644 index 0000000000..c83e1c3cfe --- /dev/null +++ b/ext/osc/ip/IpEndpointName.h @@ -0,0 +1,83 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_IPENDPOINTNAME_H +#define INCLUDED_OSCPACK_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; + + bool IsMulticastAddress() const { return ((address >> 24) & 0xFF) >= 224 && ((address >> 24) & 0xFF) <= 239; } + + 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_OSCPACK_IPENDPOINTNAME_H */ diff --git a/ext/osc/ip/NetworkingUtils.h b/ext/osc/ip/NetworkingUtils.h new file mode 100644 index 0000000000..a83612aeda --- /dev/null +++ b/ext/osc/ip/NetworkingUtils.h @@ -0,0 +1,56 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_NETWORKINGUTILS_H +#define INCLUDED_OSCPACK_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_OSCPACK_NETWORKINGUTILS_H */ diff --git a/ext/osc/ip/PacketListener.h b/ext/osc/ip/PacketListener.h new file mode 100644 index 0000000000..6c26b32996 --- /dev/null +++ b/ext/osc/ip/PacketListener.h @@ -0,0 +1,50 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_PACKETLISTENER_H +#define INCLUDED_OSCPACK_PACKETLISTENER_H + + +class IpEndpointName; + +class PacketListener{ +public: + virtual ~PacketListener() {} + virtual void ProcessPacket( const char *data, int size, + const IpEndpointName& remoteEndpoint ) = 0; +}; + +#endif /* INCLUDED_OSCPACK_PACKETLISTENER_H */ diff --git a/ext/osc/ip/TimerListener.h b/ext/osc/ip/TimerListener.h new file mode 100644 index 0000000000..59b4040600 --- /dev/null +++ b/ext/osc/ip/TimerListener.h @@ -0,0 +1,47 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_TIMERLISTENER_H +#define INCLUDED_OSCPACK_TIMERLISTENER_H + + +class TimerListener{ +public: + virtual ~TimerListener() {} + virtual void TimerExpired() = 0; +}; + +#endif /* INCLUDED_OSCPACK_TIMERLISTENER_H */ diff --git a/ext/osc/ip/UdpSocket.h b/ext/osc/ip/UdpSocket.h new file mode 100644 index 0000000000..fd18a7a8e0 --- /dev/null +++ b/ext/osc/ip/UdpSocket.h @@ -0,0 +1,177 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_UDPSOCKET_H +#define INCLUDED_OSCPACK_UDPSOCKET_H + +#include // size_t + +#include "NetworkingUtils.h" +#include "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(); + + // Enable broadcast addresses (e.g. x.x.x.255) + // Sets SO_BROADCAST socket option. + void SetEnableBroadcast( bool enableBroadcast ); + + // Enable multiple listeners for a single port on same + // network interface* + // Sets SO_REUSEADDR (also SO_REUSEPORT on OS X). + // [*] The exact behavior of SO_REUSEADDR and + // SO_REUSEPORT is undefined for some common cases + // and may have drastically different behavior on different + // operating systems. + void SetAllowReuse( bool allowReuse ); + + + // 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, std::size_t size ); + void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t 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; + + std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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() = default; + 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_OSCPACK_UDPSOCKET_H */ diff --git a/ext/osc/ip/posix/NetworkingUtils.cpp b/ext/osc/ip/posix/NetworkingUtils.cpp new file mode 100644 index 0000000000..00011c98d3 --- /dev/null +++ b/ext/osc/ip/posix/NetworkingUtils.cpp @@ -0,0 +1,64 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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 "modules/sonification/ext/osc/ip/NetworkingUtils.h" + +#include +#include +#include + +#include + + + +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; + std::memcpy( &a, h->h_addr_list[0], h->h_length ); + result = ntohl(a.s_addr); + } + + return result; +} diff --git a/ext/osc/ip/posix/UdpSocket.cpp b/ext/osc/ip/posix/UdpSocket.cpp new file mode 100644 index 0000000000..e1fcb375da --- /dev/null +++ b/ext/osc/ip/posix/UdpSocket.cpp @@ -0,0 +1,605 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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 "ip/UdpSocket.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include // for sockaddr_in + +#include +#include +#include +#include + +#include +#include +#include // for memset +#include +#include + +#include "modules/sonification/ext/osc/ip/PacketListener.h" +#include "modules/sonification/ext/osc/ip/TimerListener.h" + + +#if defined(__APPLE__) && !defined(_SOCKLEN_T) +// pre system 10.3 didn't have socklen_t +typedef ssize_t socklen_t; +#endif + + +static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) +{ + std::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"); + } + + std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); + sendToAddr_.sin_family = AF_INET; + } + + ~Implementation() + { + if (socket_ != -1) close(socket_); + } + + void SetEnableBroadcast( bool enableBroadcast ) + { + int broadcast = (enableBroadcast) ? 1 : 0; // int on posix + setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); + } + + void SetAllowReuse( bool allowReuse ) + { + int reuseAddr = (allowReuse) ? 1 : 0; // int on posix + setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)); + +#ifdef __APPLE__ + // needed also for OS X - enable multiple listeners for a single port on same network interface + int reusePort = (allowReuse) ? 1 : 0; // int on posix + setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort)); +#endif + } + + 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; + std::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; + std::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, std::size_t size ) + { + assert( isConnected_ ); + + int iResult = send( socket_, data, size, 0 ); + if(iResult == SOCKET_ERROR) { + printf("send failed with error: %d\n", WSAGetLastError()); + } + } + + void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t 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_; } + + std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) + { + assert( isBound_ ); + + struct sockaddr_in fromAddr; + socklen_t fromAddrLen = sizeof(fromAddr); + + ssize_t 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 (std::size_t)result; + } + + int Socket() { return socket_; } +}; + +UdpSocket::UdpSocket() +{ + impl_ = new Implementation(); +} + +UdpSocket::~UdpSocket() +{ + delete impl_; +} + +void UdpSocket::SetEnableBroadcast( bool enableBroadcast ) +{ + impl_->SetEnableBroadcast( enableBroadcast ); +} + +void UdpSocket::SetAllowReuse( bool allowReuse ) +{ + impl_->SetAllowReuse( allowReuse ); +} + +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, std::size_t size ) +{ + impl_->Send( data, size ); +} + +void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) +{ + impl_->SendTo( remoteEndpoint, data, size ); +} + +void UdpSocket::Bind( const IpEndpointName& localEndpoint ) +{ + impl_->Bind( localEndpoint ); +} + +bool UdpSocket::IsBound() const +{ + return impl_->IsBound(); +} + +std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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; + char *data = 0; + + try{ + + // 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; + 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; + + long timoutSecondsPart = (long)(timeoutMs * .001); + timeout.tv_sec = (time_t)timoutSecondsPart; + // 1000000 microseconds in a second + timeout.tv_usec = (suseconds_t)((timeoutMs - (timoutSecondsPart * 1000)) * 1000); + timeoutPtr = &timeout; + } + + if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 ){ + if( break_ ){ + break; + }else if( errno == EINTR ){ + // on returning an error, select() doesn't clear tempfds. + // so tempfds would remain all set, which would cause read( breakPipe_[0]... + // below to block indefinitely. therefore if select returns EINTR we restart + // the while() loop instead of continuing on to below. + continue; + }else{ + 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 ) ){ + + std::size_t size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); + if( size > 0 ){ + i->first->ProcessPacket( data, (int)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; + }catch(...){ + if( data ) + delete [] data; + throw; + } + } + + 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(); +} + diff --git a/ext/osc/ip/win32/NetworkingUtils.cpp b/ext/osc/ip/win32/NetworkingUtils.cpp new file mode 100644 index 0000000000..91f866d8ce --- /dev/null +++ b/ext/osc/ip/win32/NetworkingUtils.cpp @@ -0,0 +1,95 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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 "ip/NetworkingUtils.h" + +#include // this must come first to prevent errors with MSVC7 +#include + +#include + + +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; + std::memcpy( &a, h->h_addr_list[0], h->h_length ); + result = ntohl(a.s_addr); + } + + return result; +} diff --git a/ext/osc/ip/win32/UdpSocket.cpp b/ext/osc/ip/win32/UdpSocket.cpp new file mode 100644 index 0000000000..4fd2b12cf1 --- /dev/null +++ b/ext/osc/ip/win32/UdpSocket.cpp @@ -0,0 +1,574 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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 // this must come first to prevent errors with MSVC7 +#include +#include // for timeGetTime() + +#ifndef WINCE +#include +#endif + +#include +#include +#include // for memset +#include +#include + +#include "ip/UdpSocket.h" // usually I'd include the module header first + // but this is causing conflicts with BCB4 due to + // std::size_t usage. + +#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 ) +{ + std::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"); + } + + std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); + sendToAddr_.sin_family = AF_INET; + } + + ~Implementation() + { + if (socket_ != INVALID_SOCKET) closesocket(socket_); + } + + void SetEnableBroadcast( bool enableBroadcast ) + { + char broadcast = (char)((enableBroadcast) ? 1 : 0); // char on win32 + setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); + } + + void SetAllowReuse( bool allowReuse ) + { + // Note: SO_REUSEADDR is non-deterministic for listening sockets on Win32. See MSDN article: + // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" + // http://msdn.microsoft.com/en-us/library/ms740621%28VS.85%29.aspx + + char reuseAddr = (char)((allowReuse) ? 1 : 0); // char on win32 + setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)); + } + + 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; + std::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, std::size_t size ) + { + assert( isConnected_ ); + + int iResult = send( socket_, data, (int)size, 0 ); + if (iResult == SOCKET_ERROR) { + printf("send failed with error: %d\n", WSAGetLastError()); + } + } + + void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) + { + sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address ); + sendToAddr_.sin_port = htons( (short)remoteEndpoint.port ); + + sendto( socket_, data, (int)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_; } + + std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) + { + assert( isBound_ ); + + struct sockaddr_in fromAddr; + socklen_t fromAddrLen = sizeof(fromAddr); + + int result = recvfrom(socket_, data, (int)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_; +} + +void UdpSocket::SetEnableBroadcast( bool enableBroadcast ) +{ + impl_->SetEnableBroadcast( enableBroadcast ); +} + +void UdpSocket::SetAllowReuse( bool allowReuse ) +{ + impl_->SetAllowReuse( allowReuse ); +} + +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, std::size_t size ) +{ + impl_->Send( data, size ); +} + +void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) +{ + impl_->SendTo( remoteEndpoint, data, size ); +} + +void UdpSocket::Bind( const IpEndpointName& localEndpoint ) +{ + impl_->Bind( localEndpoint ); +} + +bool UdpSocket::IsBound() const +{ + return impl_->IsBound(); +} + +std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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(); +#ifndef WINCE + signal( SIGINT, SIG_DFL ); +#endif +} + + +class SocketReceiveMultiplexer::Implementation{ + NetworkInitializer networkInitializer_; + + std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_; + std::vector< AttachedTimerListener > timerListeners_; + + volatile bool break_; + HANDLE breakEvent_; + + double GetCurrentTimeMs() const + { +#ifndef WINCE + return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days +#else + return 0; +#endif + } + +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 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 ){ + std::size_t size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); + if( size > 0 ){ + socketListeners_[i].first->ProcessPacket( data, (int)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; +#ifndef WINCE + signal( SIGINT, InterruptSignalHandler ); +#endif + impl_->Run(); +#ifndef WINCE + signal( SIGINT, SIG_DFL ); +#endif + multiplexerInstanceToAbortWithSigInt_ = 0; +} + +void SocketReceiveMultiplexer::Break() +{ + impl_->Break(); +} + +void SocketReceiveMultiplexer::AsynchronousBreak() +{ + impl_->AsynchronousBreak(); +} + diff --git a/ext/osc/osc/MessageMappingOscPacketListener.h b/ext/osc/osc/MessageMappingOscPacketListener.h new file mode 100644 index 0000000000..bf56b530a2 --- /dev/null +++ b/ext/osc/osc/MessageMappingOscPacketListener.h @@ -0,0 +1,80 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_MESSAGEMAPPINGOSCPACKETLISTENER_H +#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H + +#include +#include + +#include "OscPacketListener.h" + + + +namespace osc{ + +template< class T > +class MessageMappingOscPacketListener : public OscPacketListener{ +public: + typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&); + +protected: + void RegisterMessageFunction( const char *addressPattern, function_type f ) + { + functions_.insert( std::make_pair( addressPattern, f ) ); + } + + virtual void ProcessMessage( const osc::ReceivedMessage& m, + const IpEndpointName& remoteEndpoint ) + { + typename function_map_type::iterator i = functions_.find( m.AddressPattern() ); + if( i != functions_.end() ) + (dynamic_cast(this)->*(i->second))( m, remoteEndpoint ); + } + +private: + struct cstr_compare{ + bool operator()( const char *lhs, const char *rhs ) const + { return std::strcmp( lhs, rhs ) < 0; } + }; + + typedef std::map function_map_type; + function_map_type functions_; +}; + +} // namespace osc + +#endif /* INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H */ \ No newline at end of file diff --git a/ext/osc/osc/OscException.h b/ext/osc/osc/OscException.h new file mode 100644 index 0000000000..73981737e0 --- /dev/null +++ b/ext/osc/osc/OscException.h @@ -0,0 +1,62 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_OSCEXCEPTION_H +#define INCLUDED_OSCPACK_OSCEXCEPTION_H + +#include + +namespace osc{ + +class Exception : public std::exception { + const char *what_; + +public: + Exception() throw() {} + Exception( const Exception& src ) throw() + : std::exception( src ) + , what_( src.what_ ) {} + Exception( const char *w ) throw() + : what_( w ) {} + Exception& operator=( const Exception& src ) throw() + { what_ = src.what_; return *this; } + virtual ~Exception() throw() {} + virtual const char* what() const throw() { return what_; } +}; + +} // namespace osc + +#endif /* INCLUDED_OSCPACK_OSCEXCEPTION_H */ diff --git a/ext/osc/osc/OscHostEndianness.h b/ext/osc/osc/OscHostEndianness.h new file mode 100644 index 0000000000..4682c473a5 --- /dev/null +++ b/ext/osc/osc/OscHostEndianness.h @@ -0,0 +1,127 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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 */ + diff --git a/ext/osc/osc/OscOutboundPacketStream.cpp b/ext/osc/osc/OscOutboundPacketStream.cpp new file mode 100644 index 0000000000..b474b4f01a --- /dev/null +++ b/ext/osc/osc/OscOutboundPacketStream.cpp @@ -0,0 +1,683 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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 "OscOutboundPacketStream.h" + +#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) +#include // for alloca +#else +//#include // alloca on Linux (also OSX) +#include // alloca on OSX and FreeBSD (and Linux?) +#endif + +#include +#include // memcpy, memmove, strcpy, strlen +#include // ptrdiff_t + +#include "OscHostEndianness.h" + +#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug +namespace std { +using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. +} +#endif + +namespace osc{ + +static void FromInt32( char *p, int32 x ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::int32 i; + char c[4]; + } u; + + u.i = x; + + p[3] = u.c[0]; + p[2] = u.c[1]; + p[1] = u.c[2]; + p[0] = u.c[3]; +#else + *reinterpret_cast(p) = x; +#endif +} + + +static void FromUInt32( char *p, uint32 x ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::uint32 i; + char c[4]; + } u; + + u.i = x; + + p[3] = u.c[0]; + p[2] = u.c[1]; + p[1] = u.c[2]; + p[0] = u.c[3]; +#else + *reinterpret_cast(p) = x; +#endif +} + + +static void FromInt64( char *p, int64 x ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::int64 i; + char c[8]; + } u; + + u.i = x; + + p[7] = u.c[0]; + p[6] = u.c[1]; + p[5] = u.c[2]; + p[4] = u.c[3]; + p[3] = u.c[4]; + p[2] = u.c[5]; + p[1] = u.c[6]; + p[0] = u.c[7]; +#else + *reinterpret_cast(p) = x; +#endif +} + + +static void FromUInt64( char *p, uint64 x ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::uint64 i; + char c[8]; + } u; + + u.i = x; + + p[7] = u.c[0]; + p[6] = u.c[1]; + p[5] = u.c[2]; + p[4] = u.c[3]; + p[3] = u.c[4]; + p[2] = u.c[5]; + p[1] = u.c[6]; + p[0] = u.c[7]; +#else + *reinterpret_cast(p) = x; +#endif +} + + +// round up to the next highest multiple of 4. unless x is already a multiple of 4 +static inline std::size_t RoundUp4( std::size_t x ) +{ + return (x + 3) & ~((std::size_t)0x03); +} + + +OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity ) + : data_( buffer ) + , end_( data_ + capacity ) + , typeTagsCurrent_( end_ ) + , messageCursor_( data_ ) + , argumentCurrent_( data_ ) + , elementSizePtr_( 0 ) + , messageIsInProgress_( false ) +{ + // sanity check integer types declared in OscTypes.h + // you'll need to fix OscTypes.h if any of these asserts fail + assert( sizeof(osc::int32) == 4 ); + assert( sizeof(osc::uint32) == 4 ); + assert( sizeof(osc::int64) == 8 ); + assert( sizeof(osc::uint64) == 8 ); +} + + +OutboundPacketStream::~OutboundPacketStream() +{ + +} + + +char *OutboundPacketStream::BeginElement( char *beginPtr ) +{ + if( elementSizePtr_ == 0 ){ + + elementSizePtr_ = reinterpret_cast(data_); + + return beginPtr; + + }else{ + // store an offset to the old element size ptr in the element size slot + // we store an offset rather than the actual pointer to be 64 bit clean. + *reinterpret_cast(beginPtr) = + (uint32)(reinterpret_cast(elementSizePtr_) - data_); + + elementSizePtr_ = reinterpret_cast(beginPtr); + + return beginPtr + 4; + } +} + + +void OutboundPacketStream::EndElement( char *endPtr ) +{ + assert( elementSizePtr_ != 0 ); + + if( elementSizePtr_ == reinterpret_cast(data_) ){ + + elementSizePtr_ = 0; + + }else{ + // while building an element, an offset to the containing element's + // size slot is stored in the elements size slot (or a ptr to data_ + // if there is no containing element). We retrieve that here + uint32 *previousElementSizePtr = + reinterpret_cast(data_ + *elementSizePtr_); + + // then we store the element size in the slot. note that the element + // size does not include the size slot, hence the - 4 below. + + std::ptrdiff_t d = endPtr - reinterpret_cast(elementSizePtr_); + // assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb + + uint32 elementSize = static_cast(d - 4); + FromUInt32( reinterpret_cast(elementSizePtr_), elementSize ); + + // finally, we reset the element size ptr to the containing element + elementSizePtr_ = previousElementSizePtr; + } +} + + +bool OutboundPacketStream::ElementSizeSlotRequired() const +{ + return (elementSizePtr_ != 0); +} + + +void OutboundPacketStream::CheckForAvailableBundleSpace() +{ + std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16; + + if( required > Capacity() ) + throw OutOfBufferMemoryException(); +} + + +void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern ) +{ + // plus 4 for at least four bytes of type tag + std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + + RoundUp4(std::strlen(addressPattern) + 1) + 4; + + if( required > Capacity() ) + throw OutOfBufferMemoryException(); +} + + +void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength ) +{ + // plus three for extra type tag, comma and null terminator + std::size_t required = (argumentCurrent_ - data_) + argumentLength + + RoundUp4( (end_ - typeTagsCurrent_) + 3 ); + + if( required > Capacity() ) + throw OutOfBufferMemoryException(); +} + + +void OutboundPacketStream::Clear() +{ + typeTagsCurrent_ = end_; + messageCursor_ = data_; + argumentCurrent_ = data_; + elementSizePtr_ = 0; + messageIsInProgress_ = false; +} + + +std::size_t OutboundPacketStream::Capacity() const +{ + return end_ - data_; +} + + +std::size_t OutboundPacketStream::Size() const +{ + std::size_t result = argumentCurrent_ - data_; + if( IsMessageInProgress() ){ + // account for the length of the type tag string. the total type tag + // includes an initial comma, plus at least one terminating \0 + result += RoundUp4( (end_ - typeTagsCurrent_) + 2 ); + } + + return result; +} + + +const char *OutboundPacketStream::Data() const +{ + return data_; +} + + +bool OutboundPacketStream::IsReady() const +{ + return (!IsMessageInProgress() && !IsBundleInProgress()); +} + + +bool OutboundPacketStream::IsMessageInProgress() const +{ + return messageIsInProgress_; +} + + +bool OutboundPacketStream::IsBundleInProgress() const +{ + return (elementSizePtr_ != 0); +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs ) +{ + if( IsMessageInProgress() ) + throw MessageInProgressException(); + + CheckForAvailableBundleSpace(); + + messageCursor_ = BeginElement( messageCursor_ ); + + std::memcpy( messageCursor_, "#bundle\0", 8 ); + FromUInt64( messageCursor_ + 8, rhs.timeTag ); + + messageCursor_ += 16; + argumentCurrent_ = messageCursor_; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs ) +{ + (void) rhs; + + if( !IsBundleInProgress() ) + throw BundleNotInProgressException(); + if( IsMessageInProgress() ) + throw MessageInProgressException(); + + EndElement( messageCursor_ ); + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs ) +{ + if( IsMessageInProgress() ) + throw MessageInProgressException(); + + CheckForAvailableMessageSpace( rhs.addressPattern ); + + messageCursor_ = BeginElement( messageCursor_ ); + + std::strcpy( messageCursor_, rhs.addressPattern ); + std::size_t rhsLength = std::strlen(rhs.addressPattern); + messageCursor_ += rhsLength + 1; + + // zero pad to 4-byte boundary + std::size_t i = rhsLength + 1; + while( i & 0x3 ){ + *messageCursor_++ = '\0'; + ++i; + } + + argumentCurrent_ = messageCursor_; + typeTagsCurrent_ = end_; + + messageIsInProgress_ = true; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs ) +{ + (void) rhs; + + if( !IsMessageInProgress() ) + throw MessageNotInProgressException(); + + std::size_t typeTagsCount = end_ - typeTagsCurrent_; + + if( typeTagsCount ){ + + char *tempTypeTags = (char*)alloca(typeTagsCount); + std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount ); + + // slot size includes comma and null terminator + std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 ); + + std::size_t argumentsSize = argumentCurrent_ - messageCursor_; + + std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize ); + + messageCursor_[0] = ','; + // copy type tags in reverse (really forward) order + for( std::size_t i=0; i < typeTagsCount; ++i ) + messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ]; + + char *p = messageCursor_ + 1 + typeTagsCount; + for( std::size_t i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i ) + *p++ = '\0'; + + typeTagsCurrent_ = end_; + + // advance messageCursor_ for next message + messageCursor_ += typeTagSlotSize + argumentsSize; + + }else{ + // send an empty type tags string + std::memcpy( messageCursor_, ",\0\0\0", 4 ); + + // advance messageCursor_ for next message + messageCursor_ += 4; + } + + argumentCurrent_ = messageCursor_; + + EndElement( messageCursor_ ); + + messageIsInProgress_ = false; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs ) +{ + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG); + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs ) +{ + (void) rhs; + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = NIL_TYPE_TAG; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs ) +{ + (void) rhs; + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs ) +{ + CheckForAvailableArgumentSpace(4); + + *(--typeTagsCurrent_) = INT32_TYPE_TAG; + FromInt32( argumentCurrent_, rhs ); + argumentCurrent_ += 4; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( float rhs ) +{ + CheckForAvailableArgumentSpace(4); + + *(--typeTagsCurrent_) = FLOAT_TYPE_TAG; + +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + float f; + char c[4]; + } u; + + u.f = rhs; + + argumentCurrent_[3] = u.c[0]; + argumentCurrent_[2] = u.c[1]; + argumentCurrent_[1] = u.c[2]; + argumentCurrent_[0] = u.c[3]; +#else + *reinterpret_cast(argumentCurrent_) = rhs; +#endif + + argumentCurrent_ += 4; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( char rhs ) +{ + CheckForAvailableArgumentSpace(4); + + *(--typeTagsCurrent_) = CHAR_TYPE_TAG; + FromInt32( argumentCurrent_, rhs ); + argumentCurrent_ += 4; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs ) +{ + CheckForAvailableArgumentSpace(4); + + *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG; + FromUInt32( argumentCurrent_, rhs ); + argumentCurrent_ += 4; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs ) +{ + CheckForAvailableArgumentSpace(4); + + *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG; + FromUInt32( argumentCurrent_, rhs ); + argumentCurrent_ += 4; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs ) +{ + CheckForAvailableArgumentSpace(8); + + *(--typeTagsCurrent_) = INT64_TYPE_TAG; + FromInt64( argumentCurrent_, rhs ); + argumentCurrent_ += 8; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs ) +{ + CheckForAvailableArgumentSpace(8); + + *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG; + FromUInt64( argumentCurrent_, rhs ); + argumentCurrent_ += 8; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( double rhs ) +{ + CheckForAvailableArgumentSpace(8); + + *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG; + +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + double f; + char c[8]; + } u; + + u.f = rhs; + + argumentCurrent_[7] = u.c[0]; + argumentCurrent_[6] = u.c[1]; + argumentCurrent_[5] = u.c[2]; + argumentCurrent_[4] = u.c[3]; + argumentCurrent_[3] = u.c[4]; + argumentCurrent_[2] = u.c[5]; + argumentCurrent_[1] = u.c[6]; + argumentCurrent_[0] = u.c[7]; +#else + *reinterpret_cast(argumentCurrent_) = rhs; +#endif + + argumentCurrent_ += 8; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) +{ + CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); + + *(--typeTagsCurrent_) = STRING_TYPE_TAG; + std::strcpy( argumentCurrent_, rhs ); + std::size_t rhsLength = std::strlen(rhs); + argumentCurrent_ += rhsLength + 1; + + // zero pad to 4-byte boundary + std::size_t i = rhsLength + 1; + while( i & 0x3 ){ + *argumentCurrent_++ = '\0'; + ++i; + } + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs ) +{ + CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); + + *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG; + std::strcpy( argumentCurrent_, rhs ); + std::size_t rhsLength = std::strlen(rhs); + argumentCurrent_ += rhsLength + 1; + + // zero pad to 4-byte boundary + std::size_t i = rhsLength + 1; + while( i & 0x3 ){ + *argumentCurrent_++ = '\0'; + ++i; + } + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs ) +{ + CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) ); + + *(--typeTagsCurrent_) = BLOB_TYPE_TAG; + FromUInt32( argumentCurrent_, rhs.size ); + argumentCurrent_ += 4; + + std::memcpy( argumentCurrent_, rhs.data, rhs.size ); + argumentCurrent_ += rhs.size; + + // zero pad to 4-byte boundary + unsigned long i = rhs.size; + while( i & 0x3 ){ + *argumentCurrent_++ = '\0'; + ++i; + } + + return *this; +} + +OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs ) +{ + (void) rhs; + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG; + + return *this; +} + +OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs ) +{ + (void) rhs; + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG; + + return *this; +} + +} // namespace osc + + diff --git a/ext/osc/osc/OscOutboundPacketStream.h b/ext/osc/osc/OscOutboundPacketStream.h new file mode 100644 index 0000000000..d0afe95421 --- /dev/null +++ b/ext/osc/osc/OscOutboundPacketStream.h @@ -0,0 +1,155 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_OSCOUTBOUNDPACKETSTREAM_H +#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H + +#include // size_t + +#include "OscTypes.h" +#include "OscException.h" + + +namespace osc{ + +class OutOfBufferMemoryException : public Exception{ +public: + OutOfBufferMemoryException( const char *w="out of buffer memory" ) + : Exception( w ) {} +}; + +class BundleNotInProgressException : public Exception{ +public: + BundleNotInProgressException( + const char *w="call to EndBundle when bundle is not in progress" ) + : Exception( w ) {} +}; + +class MessageInProgressException : public Exception{ +public: + MessageInProgressException( + const char *w="opening or closing bundle or message while message is in progress" ) + : Exception( w ) {} +}; + +class MessageNotInProgressException : public Exception{ +public: + MessageNotInProgressException( + const char *w="call to EndMessage when message is not in progress" ) + : Exception( w ) {} +}; + + +class OutboundPacketStream{ +public: + OutboundPacketStream() = default; + OutboundPacketStream( char *buffer, std::size_t capacity ); + ~OutboundPacketStream(); + + void Clear(); + + std::size_t Capacity() const; + + // invariant: size() is valid even while building a message. + std::size_t Size() const; + + const char *Data() const; + + // indicates that all messages have been closed with a matching EndMessage + // and all bundles have been closed with a matching EndBundle + bool IsReady() const; + + bool IsMessageInProgress() const; + bool IsBundleInProgress() const; + + OutboundPacketStream& operator<<( const BundleInitiator& rhs ); + OutboundPacketStream& operator<<( const BundleTerminator& rhs ); + + OutboundPacketStream& operator<<( const BeginMessage& rhs ); + OutboundPacketStream& operator<<( const MessageTerminator& rhs ); + + OutboundPacketStream& operator<<( bool rhs ); + OutboundPacketStream& operator<<( const NilType& rhs ); + OutboundPacketStream& operator<<( const InfinitumType& rhs ); + OutboundPacketStream& operator<<( int32 rhs ); + +#if !(defined(__x86_64__) || defined(_M_X64)) + OutboundPacketStream& operator<<( int rhs ) + { *this << (int32)rhs; return *this; } +#endif + + OutboundPacketStream& operator<<( float rhs ); + OutboundPacketStream& operator<<( char rhs ); + OutboundPacketStream& operator<<( const RgbaColor& rhs ); + OutboundPacketStream& operator<<( const MidiMessage& rhs ); + OutboundPacketStream& operator<<( int64 rhs ); + OutboundPacketStream& operator<<( const TimeTag& rhs ); + OutboundPacketStream& operator<<( double rhs ); + OutboundPacketStream& operator<<( const char* rhs ); + OutboundPacketStream& operator<<( const Symbol& rhs ); + OutboundPacketStream& operator<<( const Blob& rhs ); + + OutboundPacketStream& operator<<( const ArrayInitiator& rhs ); + OutboundPacketStream& operator<<( const ArrayTerminator& rhs ); + +private: + + char *BeginElement( char *beginPtr ); + void EndElement( char *endPtr ); + + bool ElementSizeSlotRequired() const; + void CheckForAvailableBundleSpace(); + void CheckForAvailableMessageSpace( const char *addressPattern ); + void CheckForAvailableArgumentSpace( std::size_t argumentLength ); + + char *data_; + char *end_; + + char *typeTagsCurrent_; // stored in reverse order + char *messageCursor_; + char *argumentCurrent_; + + // 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 */ diff --git a/ext/osc/osc/OscPacketListener.h b/ext/osc/osc/OscPacketListener.h new file mode 100644 index 0000000000..472cb1066f --- /dev/null +++ b/ext/osc/osc/OscPacketListener.h @@ -0,0 +1,79 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_OSCPACKETLISTENER_H +#define INCLUDED_OSCPACK_OSCPACKETLISTENER_H + +#include "OscReceivedElements.h" +#include "../ip/PacketListener.h" + + +namespace osc{ + +class OscPacketListener : public PacketListener{ +protected: + virtual void ProcessBundle( const osc::ReceivedBundle& b, + const IpEndpointName& remoteEndpoint ) + { + // ignore bundle time tag for now + + for( ReceivedBundle::const_iterator i = b.ElementsBegin(); + i != b.ElementsEnd(); ++i ){ + if( i->IsBundle() ) + ProcessBundle( ReceivedBundle(*i), remoteEndpoint ); + else + ProcessMessage( ReceivedMessage(*i), remoteEndpoint ); + } + } + + virtual void ProcessMessage( const osc::ReceivedMessage& m, + const IpEndpointName& remoteEndpoint ) = 0; + +public: + virtual void ProcessPacket( const char *data, int size, + const IpEndpointName& remoteEndpoint ) + { + osc::ReceivedPacket p( data, size ); + if( p.IsBundle() ) + ProcessBundle( ReceivedBundle(p), remoteEndpoint ); + else + ProcessMessage( ReceivedMessage(p), remoteEndpoint ); + } +}; + +} // namespace osc + +#endif /* INCLUDED_OSCPACK_OSCPACKETLISTENER_H */ diff --git a/ext/osc/osc/OscPrintReceivedElements.cpp b/ext/osc/osc/OscPrintReceivedElements.cpp new file mode 100644 index 0000000000..bc1689bc1d --- /dev/null +++ b/ext/osc/osc/OscPrintReceivedElements.cpp @@ -0,0 +1,261 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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 "OscPrintReceivedElements.h" + +#include +#include +#include +#include + +#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug +namespace std { +using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. +} +#endif + +namespace osc{ + + +std::ostream& operator<<( std::ostream & os, + const ReceivedMessageArgument& arg ) +{ + switch( arg.TypeTag() ){ + case TRUE_TYPE_TAG: + os << "bool:true"; + break; + + case FALSE_TYPE_TAG: + os << "bool:false"; + break; + + case NIL_TYPE_TAG: + os << "(Nil)"; + break; + + case INFINITUM_TYPE_TAG: + os << "(Infinitum)"; + break; + + case INT32_TYPE_TAG: + os << "int32:" << arg.AsInt32Unchecked(); + break; + + case FLOAT_TYPE_TAG: + os << "float32:" << arg.AsFloatUnchecked(); + break; + + case CHAR_TYPE_TAG: + { + char s[2] = {0}; + s[0] = arg.AsCharUnchecked(); + os << "char:'" << s << "'"; + } + break; + + case RGBA_COLOR_TYPE_TAG: + { + uint32 color = arg.AsRgbaColorUnchecked(); + + os << "RGBA:0x" + << std::hex << std::setfill('0') + << std::setw(2) << (int)((color>>24) & 0xFF) + << std::setw(2) << (int)((color>>16) & 0xFF) + << std::setw(2) << (int)((color>>8) & 0xFF) + << std::setw(2) << (int)(color & 0xFF) + << std::setfill(' '); + os.unsetf(std::ios::basefield); + } + break; + + case MIDI_MESSAGE_TYPE_TAG: + { + uint32 m = arg.AsMidiMessageUnchecked(); + os << "midi (port, status, data1, data2):<<" + << std::hex << std::setfill('0') + << "0x" << std::setw(2) << (int)((m>>24) & 0xFF) + << " 0x" << std::setw(2) << (int)((m>>16) & 0xFF) + << " 0x" << std::setw(2) << (int)((m>>8) & 0xFF) + << " 0x" << std::setw(2) << (int)(m & 0xFF) + << std::setfill(' ') << ">>"; + os.unsetf(std::ios::basefield); + } + break; + + case INT64_TYPE_TAG: + os << "int64:" << arg.AsInt64Unchecked(); + break; + + case TIME_TAG_TYPE_TAG: + { + os << "OSC-timetag:" << arg.AsTimeTagUnchecked() << " "; + + std::time_t t = + (unsigned long)( arg.AsTimeTagUnchecked() >> 32 ); + + const char *timeString = std::ctime( &t ); + size_t len = std::strlen( timeString ); + + // -1 to omit trailing newline from string returned by ctime() + if( len > 1 ) + os.write( timeString, len - 1 ); + } + break; + + case DOUBLE_TYPE_TAG: + os << "double:" << arg.AsDoubleUnchecked(); + break; + + case STRING_TYPE_TAG: + os << "OSC-string:`" << arg.AsStringUnchecked() << "'"; + break; + + case SYMBOL_TYPE_TAG: + os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'"; + break; + + case BLOB_TYPE_TAG: + { + const void *data; + osc_bundle_element_size_t size; + arg.AsBlobUnchecked( data, size ); + os << "OSC-blob:<<" << std::hex << std::setfill('0'); + unsigned char *p = (unsigned char*)data; + for( osc_bundle_element_size_t i = 0; i < size; ++i ){ + os << "0x" << std::setw(2) << int(p[i]); + if( i != size-1 ) + os << ' '; + } + os.unsetf(std::ios::basefield); + os << ">>" << std::setfill(' '); + } + break; + + case ARRAY_BEGIN_TYPE_TAG: + os << "["; + break; + + case ARRAY_END_TYPE_TAG: + os << "]"; + break; + + default: + os << "unknown"; + } + + return os; +} + + +std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ) +{ + os << "["; + if( m.AddressPatternIsUInt32() ) + os << m.AddressPatternAsUInt32(); + else + os << m.AddressPattern(); + + bool first = true; + for( ReceivedMessage::const_iterator i = m.ArgumentsBegin(); + i != m.ArgumentsEnd(); ++i ){ + if( first ){ + os << " "; + first = false; + }else{ + os << ", "; + } + + os << *i; + } + + os << "]"; + + return os; +} + + +std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ) +{ + static int indent = 0; + + for( int j=0; j < indent; ++j ) + os << " "; + os << "{ ( "; + if( b.TimeTag() == 1 ) + os << "immediate"; + else + os << b.TimeTag(); + os << " )\n"; + + ++indent; + + for( ReceivedBundle::const_iterator i = b.ElementsBegin(); + i != b.ElementsEnd(); ++i ){ + if( i->IsBundle() ){ + ReceivedBundle b(*i); + os << b << "\n"; + }else{ + ReceivedMessage m(*i); + for( int j=0; j < indent; ++j ) + os << " "; + os << m << "\n"; + } + } + + --indent; + + for( int j=0; j < indent; ++j ) + os << " "; + 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 diff --git a/ext/osc/osc/OscPrintReceivedElements.h b/ext/osc/osc/OscPrintReceivedElements.h new file mode 100644 index 0000000000..8d71391f0c --- /dev/null +++ b/ext/osc/osc/OscPrintReceivedElements.h @@ -0,0 +1,54 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_OSCPRINTRECEIVEDELEMENTS_H +#define INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H + +#include + +#include "OscReceivedElements.h" + + +namespace osc{ + +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 ); +std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ); + +} // namespace osc + +#endif /* INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H */ diff --git a/ext/osc/osc/OscReceivedElements.cpp b/ext/osc/osc/OscReceivedElements.cpp new file mode 100644 index 0000000000..1d57d3740a --- /dev/null +++ b/ext/osc/osc/OscReceivedElements.cpp @@ -0,0 +1,796 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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 // 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 + diff --git a/ext/osc/osc/OscReceivedElements.h b/ext/osc/osc/OscReceivedElements.h new file mode 100644 index 0000000000..b6205f3168 --- /dev/null +++ b/ext/osc/osc/OscReceivedElements.h @@ -0,0 +1,548 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_OSCRECEIVEDELEMENTS_H +#define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H + +#include +#include +#include // size_t + +#include "OscTypes.h" +#include "OscException.h" + + +namespace osc{ + + +class MalformedPacketException : public Exception{ +public: + MalformedPacketException( const char *w="malformed packet" ) + : Exception( w ) {} +}; + +class MalformedMessageException : public Exception{ +public: + MalformedMessageException( const char *w="malformed message" ) + : Exception( w ) {} +}; + +class MalformedBundleException : public Exception{ +public: + MalformedBundleException( const char *w="malformed bundle" ) + : Exception( w ) {} +}; + +class WrongArgumentTypeException : public Exception{ +public: + WrongArgumentTypeException( const char *w="wrong argument type" ) + : Exception( w ) {} +}; + +class MissingArgumentException : public Exception{ +public: + MissingArgumentException( const char *w="missing argument" ) + : Exception( w ) {} +}; + +class ExcessArgumentException : public Exception{ +public: + ExcessArgumentException( const char *w="too many arguments" ) + : Exception( w ) {} +}; + + +class ReceivedPacket{ +public: + // Although the OSC spec is not entirely clear on this, we only support + // packets up to 0x7FFFFFFC bytes long (the maximum 4-byte aligned value + // representable by an int32). An exception will be raised if you pass a + // larger value to the ReceivedPacket() constructor. + + ReceivedPacket( const char *contents, osc_bundle_element_size_t size ) + : contents_( contents ) + , size_( ValidateSize(size) ) {} + + ReceivedPacket( const char *contents, std::size_t size ) + : contents_( contents ) + , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} + +#if !(defined(__x86_64__) || defined(_M_X64)) + ReceivedPacket( const char *contents, int size ) + : contents_( contents ) + , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} +#endif + + bool IsMessage() const { return !IsBundle(); } + bool IsBundle() const; + + osc_bundle_element_size_t Size() const { return size_; } + const char *Contents() const { return contents_; } + +private: + const char *contents_; + osc_bundle_element_size_t size_; + + static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size ) + { + // sanity check integer types declared in OscTypes.h + // you'll need to fix OscTypes.h if any of these asserts fail + assert( sizeof(osc::int32) == 4 ); + assert( sizeof(osc::uint32) == 4 ); + assert( sizeof(osc::int64) == 8 ); + assert( sizeof(osc::uint64) == 8 ); + + if( !IsValidElementSizeValue(size) ) + throw MalformedPacketException( "invalid packet size" ); + + if( size == 0 ) + throw MalformedPacketException( "zero length elements not permitted" ); + + if( !IsMultipleOf4(size) ) + throw MalformedPacketException( "element size must be multiple of four" ); + + return size; + } +}; + + +class ReceivedBundleElement{ +public: + ReceivedBundleElement( const char *sizePtr ) + : sizePtr_( sizePtr ) {} + + friend class ReceivedBundleElementIterator; + + bool IsMessage() const { return !IsBundle(); } + bool IsBundle() const; + + osc_bundle_element_size_t Size() const; + const char *Contents() const { return sizePtr_ + osc::OSC_SIZEOF_INT32; } + +private: + const char *sizePtr_; +}; + + +class ReceivedBundleElementIterator{ +public: + ReceivedBundleElementIterator( const char *sizePtr ) + : value_( sizePtr ) {} + + ReceivedBundleElementIterator operator++() + { + Advance(); + return *this; + } + + ReceivedBundleElementIterator operator++(int) + { + ReceivedBundleElementIterator old( *this ); + Advance(); + return old; + } + + const ReceivedBundleElement& operator*() const { return value_; } + + const ReceivedBundleElement* operator->() const { return &value_; } + + friend bool operator==(const ReceivedBundleElementIterator& lhs, + const ReceivedBundleElementIterator& rhs ); + +private: + ReceivedBundleElement value_; + + void Advance() { value_.sizePtr_ = value_.Contents() + value_.Size(); } + + bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const + { + return value_.sizePtr_ == rhs.value_.sizePtr_; + } +}; + +inline bool operator==(const ReceivedBundleElementIterator& lhs, + const ReceivedBundleElementIterator& rhs ) +{ + return lhs.IsEqualTo( rhs ); +} + +inline bool operator!=(const ReceivedBundleElementIterator& lhs, + const ReceivedBundleElementIterator& rhs ) +{ + return !( lhs == rhs ); +} + + +class ReceivedMessageArgument{ +public: + ReceivedMessageArgument( const char *typeTagPtr, const char *argumentPtr ) + : typeTagPtr_( typeTagPtr ) + , argumentPtr_( argumentPtr ) {} + + friend class ReceivedMessageArgumentIterator; + + char TypeTag() const { return *typeTagPtr_; } + + // the unchecked methods below don't check whether the argument actually + // is of the specified type. they should only be used if you've already + // checked the type tag or the associated IsType() method. + + bool IsBool() const + { return *typeTagPtr_ == TRUE_TYPE_TAG || *typeTagPtr_ == FALSE_TYPE_TAG; } + bool AsBool() const; + bool AsBoolUnchecked() const; + + bool IsNil() const { return *typeTagPtr_ == NIL_TYPE_TAG; } + bool IsInfinitum() const { return *typeTagPtr_ == INFINITUM_TYPE_TAG; } + + bool IsInt32() const { return *typeTagPtr_ == INT32_TYPE_TAG; } + int32 AsInt32() const; + int32 AsInt32Unchecked() const; + + bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; } + float AsFloat() const; + float AsFloatUnchecked() const; + + bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; } + char AsChar() const; + char AsCharUnchecked() const; + + bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; } + uint32 AsRgbaColor() const; + uint32 AsRgbaColorUnchecked() const; + + bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; } + uint32 AsMidiMessage() const; + uint32 AsMidiMessageUnchecked() const; + + bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; } + int64 AsInt64() const; + int64 AsInt64Unchecked() const; + + bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; } + uint64 AsTimeTag() const; + uint64 AsTimeTagUnchecked() const; + + bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; } + double AsDouble() const; + double AsDoubleUnchecked() const; + + bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; } + const char* AsString() const; + const char* AsStringUnchecked() const { return argumentPtr_; } + + bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; } + const char* AsSymbol() const; + const char* AsSymbolUnchecked() const { return argumentPtr_; } + + bool IsBlob() const { return *typeTagPtr_ == BLOB_TYPE_TAG; } + void AsBlob( const void*& data, osc_bundle_element_size_t& size ) const; + void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const; + + bool IsArrayBegin() const { return *typeTagPtr_ == ARRAY_BEGIN_TYPE_TAG; } + bool IsArrayEnd() const { return *typeTagPtr_ == ARRAY_END_TYPE_TAG; } + // Calculate the number of top-level items in the array. Nested arrays count as one item. + // Only valid at array start. Will throw an exception if IsArrayStart() == false. + std::size_t ComputeArrayItemCount() const; + +private: + const char *typeTagPtr_; + const char *argumentPtr_; +}; + + +class ReceivedMessageArgumentIterator{ +public: + ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments ) + : value_( typeTags, arguments ) {} + + ReceivedMessageArgumentIterator operator++() + { + Advance(); + return *this; + } + + ReceivedMessageArgumentIterator operator++(int) + { + ReceivedMessageArgumentIterator old( *this ); + Advance(); + return old; + } + + const ReceivedMessageArgument& operator*() const { return value_; } + + const ReceivedMessageArgument* operator->() const { return &value_; } + + friend bool operator==(const ReceivedMessageArgumentIterator& lhs, + const ReceivedMessageArgumentIterator& rhs ); + +private: + ReceivedMessageArgument value_; + + void Advance(); + + bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const + { + return value_.typeTagPtr_ == rhs.value_.typeTagPtr_; + } +}; + +inline bool operator==(const ReceivedMessageArgumentIterator& lhs, + const ReceivedMessageArgumentIterator& rhs ) +{ + return lhs.IsEqualTo( rhs ); +} + +inline bool operator!=(const ReceivedMessageArgumentIterator& lhs, + const ReceivedMessageArgumentIterator& rhs ) +{ + return !( lhs == rhs ); +} + + +class ReceivedMessageArgumentStream{ + friend class ReceivedMessage; + ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin, + const ReceivedMessageArgumentIterator& end ) + : p_( begin ) + , end_( end ) {} + + ReceivedMessageArgumentIterator p_, end_; + +public: + + // end of stream + bool Eos() const { return p_ == end_; } + + ReceivedMessageArgumentStream& operator>>( bool& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsBool(); + return *this; + } + + // not sure if it would be useful to stream Nil and Infinitum + // for now it's not possible + // same goes for array boundaries + + ReceivedMessageArgumentStream& operator>>( int32& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsInt32(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( float& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsFloat(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( char& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsChar(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsRgbaColor(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsMidiMessage(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( int64& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsInt64(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( TimeTag& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsTimeTag(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( double& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsDouble(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( Blob& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + (*p_++).AsBlob( rhs.data, rhs.size ); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( const char*& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsString(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( Symbol& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsSymbol(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) + { + (void) rhs; // suppress unused parameter warning + + if( !Eos() ) + throw ExcessArgumentException(); + + return *this; + } +}; + + +class ReceivedMessage{ + void Init( const char *bundle, osc_bundle_element_size_t size ); +public: + explicit ReceivedMessage( const ReceivedPacket& packet ); + explicit ReceivedMessage( const ReceivedBundleElement& bundleElement ); + + const char *AddressPattern() const { return addressPattern_; } + + // Support for non-standard SuperCollider integer address patterns: + bool AddressPatternIsUInt32() const; + uint32 AddressPatternAsUInt32() const; + + uint32 ArgumentCount() const { return static_cast(typeTagsEnd_ - typeTagsBegin_); } + + const char *TypeTags() const { return typeTagsBegin_; } + + + typedef ReceivedMessageArgumentIterator const_iterator; + + ReceivedMessageArgumentIterator ArgumentsBegin() const + { + return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ ); + } + + ReceivedMessageArgumentIterator ArgumentsEnd() const + { + return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 ); + } + + ReceivedMessageArgumentStream ArgumentStream() const + { + return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() ); + } + +private: + const char *addressPattern_; + const char *typeTagsBegin_; + const char *typeTagsEnd_; + const char *arguments_; +}; + + +class ReceivedBundle{ + void Init( const char *message, osc_bundle_element_size_t size ); +public: + explicit ReceivedBundle( const ReceivedPacket& packet ); + explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); + + uint64 TimeTag() const; + + uint32 ElementCount() const { return elementCount_; } + + typedef ReceivedBundleElementIterator const_iterator; + + ReceivedBundleElementIterator ElementsBegin() const + { + return ReceivedBundleElementIterator( timeTag_ + 8 ); + } + + ReceivedBundleElementIterator ElementsEnd() const + { + return ReceivedBundleElementIterator( end_ ); + } + +private: + const char *timeTag_; + const char *end_; + uint32 elementCount_; +}; + + +} // namespace osc + + +#endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */ diff --git a/ext/osc/osc/OscTypes.cpp b/ext/osc/osc/OscTypes.cpp new file mode 100644 index 0000000000..444a9fed48 --- /dev/null +++ b/ext/osc/osc/OscTypes.cpp @@ -0,0 +1,52 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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 "OscTypes.h" + +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 diff --git a/ext/osc/osc/OscTypes.h b/ext/osc/osc/OscTypes.h new file mode 100644 index 0000000000..610020182e --- /dev/null +++ b/ext/osc/osc/OscTypes.h @@ -0,0 +1,240 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + 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_OSCTYPES_H +#define INCLUDED_OSCPACK_OSCTYPES_H + + +namespace osc{ + +// basic types + +#if defined(__BORLANDC__) || defined(_MSC_VER) + +typedef __int64 int64; +typedef unsigned __int64 uint64; + +#elif defined(__x86_64__) || defined(_M_X64) + +typedef long int64; +typedef unsigned long uint64; + +#else + +typedef long long int64; +typedef unsigned long long uint64; + +#endif + + + +#if defined(__x86_64__) || defined(_M_X64) + +typedef signed int int32; +typedef unsigned int uint32; + +#else + +typedef signed long int32; +typedef unsigned long uint32; + +#endif + + +enum ValueTypeSizes{ + OSC_SIZEOF_INT32 = 4, + OSC_SIZEOF_UINT32 = 4, + OSC_SIZEOF_INT64 = 8, + OSC_SIZEOF_UINT64 = 8, +}; + + +// osc_bundle_element_size_t is used for the size of bundle elements and blobs +// the OSC spec specifies these as int32 (signed) but we ensure that they +// are always positive since negative field sizes make no sense. + +typedef int32 osc_bundle_element_size_t; + +enum { + OSC_INT32_MAX = 0x7FFFFFFF, + + // Element sizes are specified to be int32, and are always rounded up to nearest + // multiple of 4. Therefore their values can't be greater than 0x7FFFFFFC. + OSC_BUNDLE_ELEMENT_SIZE_MAX = 0x7FFFFFFC +}; + + +inline bool IsValidElementSizeValue( osc_bundle_element_size_t x ) +{ + // sizes may not be negative or exceed OSC_BUNDLE_ELEMENT_SIZE_MAX + return x >= 0 && x <= OSC_BUNDLE_ELEMENT_SIZE_MAX; +} + + +inline bool IsMultipleOf4( osc_bundle_element_size_t x ) +{ + return (x & ((osc_bundle_element_size_t)0x03)) == 0; +} + + +enum TypeTagValues { + TRUE_TYPE_TAG = 'T', + FALSE_TYPE_TAG = 'F', + NIL_TYPE_TAG = 'N', + INFINITUM_TYPE_TAG = 'I', + INT32_TYPE_TAG = 'i', + FLOAT_TYPE_TAG = 'f', + CHAR_TYPE_TAG = 'c', + RGBA_COLOR_TYPE_TAG = 'r', + MIDI_MESSAGE_TYPE_TAG = 'm', + INT64_TYPE_TAG = 'h', + TIME_TAG_TYPE_TAG = 't', + DOUBLE_TYPE_TAG = 'd', + STRING_TYPE_TAG = 's', + SYMBOL_TYPE_TAG = 'S', + BLOB_TYPE_TAG = 'b', + ARRAY_BEGIN_TYPE_TAG = '[', + ARRAY_END_TYPE_TAG = ']' +}; + + + +// i/o manipulators used for streaming interfaces + +struct BundleInitiator{ + explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {} + uint64 timeTag; +}; + +extern BundleInitiator BeginBundleImmediate; + +inline BundleInitiator BeginBundle( uint64 timeTag=1 ) +{ + return BundleInitiator(timeTag); +} + + +struct BundleTerminator{ +}; + +extern BundleTerminator EndBundle; + +struct BeginMessage{ + explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {} + const char *addressPattern; +}; + +struct MessageTerminator{ +}; + +extern MessageTerminator EndMessage; + + +// osc specific types. they are defined as structs so they can be used +// as separately identifiable types with the streaming operators. + +struct NilType{ +}; + +extern NilType OscNil; + +#ifndef _OBJC_OBJC_H_ +extern NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead +#endif + +struct InfinitumType{ +}; + +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 */ From e14121741a702a17043ff46ad7842ec0ec7748e2 Mon Sep 17 00:00:00 2001 From: Malin E Date: Tue, 7 Dec 2021 09:05:16 +0100 Subject: [PATCH 5/7] Dont spam warning for too many axes or buttons on joystick --- apps/OpenSpace/main.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 063057d6a5..24bc01d5dc 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -369,30 +369,33 @@ void mainPreSyncFunc() { std::fill(state.axes.begin(), state.axes.end(), 0.f); std::fill(state.buttons.begin(), state.buttons.end(), JoystickAction::Idle); + + // Check axes and buttons + glfwGetJoystickAxes(i, &state.nAxes); + if (state.nAxes > JoystickInputState::MaxAxes) { + LWARNING(fmt::format( + "Joystick/Gamepad {} has {} axes, but only {} axes are supported. " + "All excess axes are ignored", + state.name, state.nAxes, JoystickInputState::MaxAxes + )); + state.nAxes = JoystickInputState::MaxAxes; + } + glfwGetJoystickButtons(i, &state.nButtons); + if (state.nButtons > JoystickInputState::MaxButtons) { + LWARNING(fmt::format( + "Joystick/Gamepad {} has {} buttons, but only {} buttons are " + "supported. All excess buttons are ignored", + state.name, state.nButtons, JoystickInputState::MaxButtons + )); + state.nButtons = JoystickInputState::MaxButtons; + } } const float* axes = glfwGetJoystickAxes(i, &state.nAxes); - if (state.nAxes > JoystickInputState::MaxAxes) { - LWARNING(fmt::format( - "Joystick/Gamepad {} has {} axes, but only {} axes are supported. " - "All excess axes are ignored", - state.name, state.nAxes, JoystickInputState::MaxAxes - )); - state.nAxes = JoystickInputState::MaxAxes; - } std::memcpy(state.axes.data(), axes, state.nAxes * sizeof(float)); const unsigned char* buttons = glfwGetJoystickButtons(i, &state.nButtons); - if (state.nButtons > JoystickInputState::MaxButtons) { - LWARNING(fmt::format( - "Joystick/Gamepad {} has {} buttons, but only {} buttons are " - "supported. All excess buttons are ignored", - state.name, state.nButtons, JoystickInputState::MaxButtons - )); - state.nButtons = JoystickInputState::MaxButtons; - } - for (int j = 0; j < state.nButtons; ++j) { const bool currentlyPressed = buttons[j] == GLFW_PRESS; From a3ba8ee808925759ba9a4ea863a569f97b52b847 Mon Sep 17 00:00:00 2001 From: Malin E Date: Tue, 7 Dec 2021 10:52:04 +0100 Subject: [PATCH 6/7] Remove excess axes or buttons if too many present on joystick --- apps/OpenSpace/main.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 24bc01d5dc..b761225f75 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -378,7 +378,6 @@ void mainPreSyncFunc() { "All excess axes are ignored", state.name, state.nAxes, JoystickInputState::MaxAxes )); - state.nAxes = JoystickInputState::MaxAxes; } glfwGetJoystickButtons(i, &state.nButtons); if (state.nButtons > JoystickInputState::MaxButtons) { @@ -387,14 +386,19 @@ void mainPreSyncFunc() { "supported. All excess buttons are ignored", state.name, state.nButtons, JoystickInputState::MaxButtons )); - state.nButtons = JoystickInputState::MaxButtons; } } const float* axes = glfwGetJoystickAxes(i, &state.nAxes); + if (state.nAxes > JoystickInputState::MaxAxes) { + state.nAxes = JoystickInputState::MaxAxes; + } std::memcpy(state.axes.data(), axes, state.nAxes * sizeof(float)); const unsigned char* buttons = glfwGetJoystickButtons(i, &state.nButtons); + if (state.nButtons > JoystickInputState::MaxButtons) { + state.nButtons = JoystickInputState::MaxButtons; + } for (int j = 0; j < state.nButtons; ++j) { const bool currentlyPressed = buttons[j] == GLFW_PRESS; From cfd8b145f3af709d6aa870c1acf7ef80d8b1dc39 Mon Sep 17 00:00:00 2001 From: Malin E Date: Tue, 7 Dec 2021 11:07:05 +0100 Subject: [PATCH 7/7] Remove osc files that should not be here --- ext/osc/CMakeLists.txt | 53 -- ext/osc/LICENSE | 34 - ext/osc/ip/IpEndpointName.cpp | 88 -- ext/osc/ip/IpEndpointName.h | 83 -- ext/osc/ip/NetworkingUtils.h | 56 -- ext/osc/ip/PacketListener.h | 50 -- ext/osc/ip/TimerListener.h | 47 -- ext/osc/ip/UdpSocket.h | 177 ---- ext/osc/ip/posix/NetworkingUtils.cpp | 64 -- ext/osc/ip/posix/UdpSocket.cpp | 605 ------------- ext/osc/ip/win32/NetworkingUtils.cpp | 95 --- ext/osc/ip/win32/UdpSocket.cpp | 574 ------------- ext/osc/osc/MessageMappingOscPacketListener.h | 80 -- ext/osc/osc/OscException.h | 62 -- ext/osc/osc/OscHostEndianness.h | 127 --- ext/osc/osc/OscOutboundPacketStream.cpp | 683 --------------- ext/osc/osc/OscOutboundPacketStream.h | 155 ---- ext/osc/osc/OscPacketListener.h | 79 -- ext/osc/osc/OscPrintReceivedElements.cpp | 261 ------ ext/osc/osc/OscPrintReceivedElements.h | 54 -- ext/osc/osc/OscReceivedElements.cpp | 796 ------------------ ext/osc/osc/OscReceivedElements.h | 548 ------------ ext/osc/osc/OscTypes.cpp | 52 -- ext/osc/osc/OscTypes.h | 240 ------ 24 files changed, 5063 deletions(-) delete mode 100644 ext/osc/CMakeLists.txt delete mode 100644 ext/osc/LICENSE delete mode 100644 ext/osc/ip/IpEndpointName.cpp delete mode 100644 ext/osc/ip/IpEndpointName.h delete mode 100644 ext/osc/ip/NetworkingUtils.h delete mode 100644 ext/osc/ip/PacketListener.h delete mode 100644 ext/osc/ip/TimerListener.h delete mode 100644 ext/osc/ip/UdpSocket.h delete mode 100644 ext/osc/ip/posix/NetworkingUtils.cpp delete mode 100644 ext/osc/ip/posix/UdpSocket.cpp delete mode 100644 ext/osc/ip/win32/NetworkingUtils.cpp delete mode 100644 ext/osc/ip/win32/UdpSocket.cpp delete mode 100644 ext/osc/osc/MessageMappingOscPacketListener.h delete mode 100644 ext/osc/osc/OscException.h delete mode 100644 ext/osc/osc/OscHostEndianness.h delete mode 100644 ext/osc/osc/OscOutboundPacketStream.cpp delete mode 100644 ext/osc/osc/OscOutboundPacketStream.h delete mode 100644 ext/osc/osc/OscPacketListener.h delete mode 100644 ext/osc/osc/OscPrintReceivedElements.cpp delete mode 100644 ext/osc/osc/OscPrintReceivedElements.h delete mode 100644 ext/osc/osc/OscReceivedElements.cpp delete mode 100644 ext/osc/osc/OscReceivedElements.h delete mode 100644 ext/osc/osc/OscTypes.cpp delete mode 100644 ext/osc/osc/OscTypes.h diff --git a/ext/osc/CMakeLists.txt b/ext/osc/CMakeLists.txt deleted file mode 100644 index 27c30e8a18..0000000000 --- a/ext/osc/CMakeLists.txt +++ /dev/null @@ -1,53 +0,0 @@ -cmake_minimum_required(VERSION 2.6) -PROJECT(Oscpack) -message(STATUS "Generating oscpack project") - -# separate versions of NetworkingUtils.cpp and UdpSocket.cpp are provided for Win32 and POSIX -# the IpSystemTypePath selects the correct ones based on the current platform - -IF(WIN32) - set(IpSystemTypePath ip/win32) -ELSE(WIN32) - set(IpSystemTypePath ip/posix) -ENDIF(WIN32) - -ADD_LIBRARY(oscpack - ip/IpEndpointName.h - ip/IpEndpointName.cpp - ip/NetworkingUtils.h - ${IpSystemTypePath}/NetworkingUtils.cpp - ip/UdpSocket.h - ${IpSystemTypePath}/UdpSocket.cpp - ip/PacketListener.h - ip/TimerListener.h - osc/OscTypes.h - osc/OscTypes.cpp - osc/OscHostEndianness.h - osc/OscException.h - osc/OscPacketListener.h - osc/MessageMappingOscPacketListener.h - osc/OscReceivedElements.h - osc/OscReceivedElements.cpp - osc/OscPrintReceivedElements.h - osc/OscPrintReceivedElements.cpp - osc/OscOutboundPacketStream.h - osc/OscOutboundPacketStream.cpp -) - -TARGET_INCLUDE_DIRECTORIES(oscpack PUBLIC ${CMAKE_SOURCE_DIR}) - -IF(WIN32) - target_link_libraries(oscpack PUBLIC Ws2_32 winmm) -ENDIF(WIN32) - -if(MSVC) - # Force to always compile with W4 - if(CMAKE_CXX_FLAGS MATCHES /W[0-4]) - string(REGEX REPLACE /W[0-4] /W4 CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - else() - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} /W4) - endif() -elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - # Update if necessary - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-long-long -pedantic) -endif() diff --git a/ext/osc/LICENSE b/ext/osc/LICENSE deleted file mode 100644 index ebaaac1977..0000000000 --- a/ext/osc/LICENSE +++ /dev/null @@ -1,34 +0,0 @@ -oscpack -- Open Sound Control (OSC) packet manipulation library -http://www.rossbencina.com/code/oscpack - -Copyright (c) 2004-2013 Ross Bencina - -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. \ No newline at end of file diff --git a/ext/osc/ip/IpEndpointName.cpp b/ext/osc/ip/IpEndpointName.cpp deleted file mode 100644 index 50b0262216..0000000000 --- a/ext/osc/ip/IpEndpointName.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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 "IpEndpointName.h" - -#include - -#include "NetworkingUtils.h" - - -unsigned long IpEndpointName::GetHostByName( const char *s ) -{ - return ::GetHostByName(s); -} - - -void IpEndpointName::AddressAsString( char *s ) const -{ - if( address == ANY_ADDRESS ){ - std::sprintf( s, "" ); - }else{ - std::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 ){ - std::sprintf( s, ":" ); - }else{ - std::sprintf( s, "%d.%d.%d.%d:", - (int)((address >> 24) & 0xFF), - (int)((address >> 16) & 0xFF), - (int)((address >> 8) & 0xFF), - (int)(address & 0xFF) ); - } - }else{ - if( address == ANY_ADDRESS ){ - std::sprintf( s, ":%d", port ); - }else{ - std::sprintf( s, "%d.%d.%d.%d:%d", - (int)((address >> 24) & 0xFF), - (int)((address >> 16) & 0xFF), - (int)((address >> 8) & 0xFF), - (int)(address & 0xFF), - (int)port ); - } - } -} diff --git a/ext/osc/ip/IpEndpointName.h b/ext/osc/ip/IpEndpointName.h deleted file mode 100644 index c83e1c3cfe..0000000000 --- a/ext/osc/ip/IpEndpointName.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_IPENDPOINTNAME_H -#define INCLUDED_OSCPACK_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; - - bool IsMulticastAddress() const { return ((address >> 24) & 0xFF) >= 224 && ((address >> 24) & 0xFF) <= 239; } - - 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_OSCPACK_IPENDPOINTNAME_H */ diff --git a/ext/osc/ip/NetworkingUtils.h b/ext/osc/ip/NetworkingUtils.h deleted file mode 100644 index a83612aeda..0000000000 --- a/ext/osc/ip/NetworkingUtils.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_NETWORKINGUTILS_H -#define INCLUDED_OSCPACK_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_OSCPACK_NETWORKINGUTILS_H */ diff --git a/ext/osc/ip/PacketListener.h b/ext/osc/ip/PacketListener.h deleted file mode 100644 index 6c26b32996..0000000000 --- a/ext/osc/ip/PacketListener.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_PACKETLISTENER_H -#define INCLUDED_OSCPACK_PACKETLISTENER_H - - -class IpEndpointName; - -class PacketListener{ -public: - virtual ~PacketListener() {} - virtual void ProcessPacket( const char *data, int size, - const IpEndpointName& remoteEndpoint ) = 0; -}; - -#endif /* INCLUDED_OSCPACK_PACKETLISTENER_H */ diff --git a/ext/osc/ip/TimerListener.h b/ext/osc/ip/TimerListener.h deleted file mode 100644 index 59b4040600..0000000000 --- a/ext/osc/ip/TimerListener.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_TIMERLISTENER_H -#define INCLUDED_OSCPACK_TIMERLISTENER_H - - -class TimerListener{ -public: - virtual ~TimerListener() {} - virtual void TimerExpired() = 0; -}; - -#endif /* INCLUDED_OSCPACK_TIMERLISTENER_H */ diff --git a/ext/osc/ip/UdpSocket.h b/ext/osc/ip/UdpSocket.h deleted file mode 100644 index fd18a7a8e0..0000000000 --- a/ext/osc/ip/UdpSocket.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_UDPSOCKET_H -#define INCLUDED_OSCPACK_UDPSOCKET_H - -#include // size_t - -#include "NetworkingUtils.h" -#include "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(); - - // Enable broadcast addresses (e.g. x.x.x.255) - // Sets SO_BROADCAST socket option. - void SetEnableBroadcast( bool enableBroadcast ); - - // Enable multiple listeners for a single port on same - // network interface* - // Sets SO_REUSEADDR (also SO_REUSEPORT on OS X). - // [*] The exact behavior of SO_REUSEADDR and - // SO_REUSEPORT is undefined for some common cases - // and may have drastically different behavior on different - // operating systems. - void SetAllowReuse( bool allowReuse ); - - - // 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, std::size_t size ); - void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t 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; - - std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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() = default; - 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_OSCPACK_UDPSOCKET_H */ diff --git a/ext/osc/ip/posix/NetworkingUtils.cpp b/ext/osc/ip/posix/NetworkingUtils.cpp deleted file mode 100644 index 00011c98d3..0000000000 --- a/ext/osc/ip/posix/NetworkingUtils.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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 "modules/sonification/ext/osc/ip/NetworkingUtils.h" - -#include -#include -#include - -#include - - - -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; - std::memcpy( &a, h->h_addr_list[0], h->h_length ); - result = ntohl(a.s_addr); - } - - return result; -} diff --git a/ext/osc/ip/posix/UdpSocket.cpp b/ext/osc/ip/posix/UdpSocket.cpp deleted file mode 100644 index e1fcb375da..0000000000 --- a/ext/osc/ip/posix/UdpSocket.cpp +++ /dev/null @@ -1,605 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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 "ip/UdpSocket.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include // for sockaddr_in - -#include -#include -#include -#include - -#include -#include -#include // for memset -#include -#include - -#include "modules/sonification/ext/osc/ip/PacketListener.h" -#include "modules/sonification/ext/osc/ip/TimerListener.h" - - -#if defined(__APPLE__) && !defined(_SOCKLEN_T) -// pre system 10.3 didn't have socklen_t -typedef ssize_t socklen_t; -#endif - - -static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) -{ - std::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"); - } - - std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); - sendToAddr_.sin_family = AF_INET; - } - - ~Implementation() - { - if (socket_ != -1) close(socket_); - } - - void SetEnableBroadcast( bool enableBroadcast ) - { - int broadcast = (enableBroadcast) ? 1 : 0; // int on posix - setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); - } - - void SetAllowReuse( bool allowReuse ) - { - int reuseAddr = (allowReuse) ? 1 : 0; // int on posix - setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)); - -#ifdef __APPLE__ - // needed also for OS X - enable multiple listeners for a single port on same network interface - int reusePort = (allowReuse) ? 1 : 0; // int on posix - setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort)); -#endif - } - - 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; - std::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; - std::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, std::size_t size ) - { - assert( isConnected_ ); - - int iResult = send( socket_, data, size, 0 ); - if(iResult == SOCKET_ERROR) { - printf("send failed with error: %d\n", WSAGetLastError()); - } - } - - void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t 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_; } - - std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) - { - assert( isBound_ ); - - struct sockaddr_in fromAddr; - socklen_t fromAddrLen = sizeof(fromAddr); - - ssize_t 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 (std::size_t)result; - } - - int Socket() { return socket_; } -}; - -UdpSocket::UdpSocket() -{ - impl_ = new Implementation(); -} - -UdpSocket::~UdpSocket() -{ - delete impl_; -} - -void UdpSocket::SetEnableBroadcast( bool enableBroadcast ) -{ - impl_->SetEnableBroadcast( enableBroadcast ); -} - -void UdpSocket::SetAllowReuse( bool allowReuse ) -{ - impl_->SetAllowReuse( allowReuse ); -} - -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, std::size_t size ) -{ - impl_->Send( data, size ); -} - -void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) -{ - impl_->SendTo( remoteEndpoint, data, size ); -} - -void UdpSocket::Bind( const IpEndpointName& localEndpoint ) -{ - impl_->Bind( localEndpoint ); -} - -bool UdpSocket::IsBound() const -{ - return impl_->IsBound(); -} - -std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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; - char *data = 0; - - try{ - - // 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; - 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; - - long timoutSecondsPart = (long)(timeoutMs * .001); - timeout.tv_sec = (time_t)timoutSecondsPart; - // 1000000 microseconds in a second - timeout.tv_usec = (suseconds_t)((timeoutMs - (timoutSecondsPart * 1000)) * 1000); - timeoutPtr = &timeout; - } - - if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 ){ - if( break_ ){ - break; - }else if( errno == EINTR ){ - // on returning an error, select() doesn't clear tempfds. - // so tempfds would remain all set, which would cause read( breakPipe_[0]... - // below to block indefinitely. therefore if select returns EINTR we restart - // the while() loop instead of continuing on to below. - continue; - }else{ - 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 ) ){ - - std::size_t size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); - if( size > 0 ){ - i->first->ProcessPacket( data, (int)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; - }catch(...){ - if( data ) - delete [] data; - throw; - } - } - - 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(); -} - diff --git a/ext/osc/ip/win32/NetworkingUtils.cpp b/ext/osc/ip/win32/NetworkingUtils.cpp deleted file mode 100644 index 91f866d8ce..0000000000 --- a/ext/osc/ip/win32/NetworkingUtils.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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 "ip/NetworkingUtils.h" - -#include // this must come first to prevent errors with MSVC7 -#include - -#include - - -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; - std::memcpy( &a, h->h_addr_list[0], h->h_length ); - result = ntohl(a.s_addr); - } - - return result; -} diff --git a/ext/osc/ip/win32/UdpSocket.cpp b/ext/osc/ip/win32/UdpSocket.cpp deleted file mode 100644 index 4fd2b12cf1..0000000000 --- a/ext/osc/ip/win32/UdpSocket.cpp +++ /dev/null @@ -1,574 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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 // this must come first to prevent errors with MSVC7 -#include -#include // for timeGetTime() - -#ifndef WINCE -#include -#endif - -#include -#include -#include // for memset -#include -#include - -#include "ip/UdpSocket.h" // usually I'd include the module header first - // but this is causing conflicts with BCB4 due to - // std::size_t usage. - -#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 ) -{ - std::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"); - } - - std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); - sendToAddr_.sin_family = AF_INET; - } - - ~Implementation() - { - if (socket_ != INVALID_SOCKET) closesocket(socket_); - } - - void SetEnableBroadcast( bool enableBroadcast ) - { - char broadcast = (char)((enableBroadcast) ? 1 : 0); // char on win32 - setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); - } - - void SetAllowReuse( bool allowReuse ) - { - // Note: SO_REUSEADDR is non-deterministic for listening sockets on Win32. See MSDN article: - // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" - // http://msdn.microsoft.com/en-us/library/ms740621%28VS.85%29.aspx - - char reuseAddr = (char)((allowReuse) ? 1 : 0); // char on win32 - setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)); - } - - 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; - std::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, std::size_t size ) - { - assert( isConnected_ ); - - int iResult = send( socket_, data, (int)size, 0 ); - if (iResult == SOCKET_ERROR) { - printf("send failed with error: %d\n", WSAGetLastError()); - } - } - - void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) - { - sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address ); - sendToAddr_.sin_port = htons( (short)remoteEndpoint.port ); - - sendto( socket_, data, (int)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_; } - - std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) - { - assert( isBound_ ); - - struct sockaddr_in fromAddr; - socklen_t fromAddrLen = sizeof(fromAddr); - - int result = recvfrom(socket_, data, (int)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_; -} - -void UdpSocket::SetEnableBroadcast( bool enableBroadcast ) -{ - impl_->SetEnableBroadcast( enableBroadcast ); -} - -void UdpSocket::SetAllowReuse( bool allowReuse ) -{ - impl_->SetAllowReuse( allowReuse ); -} - -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, std::size_t size ) -{ - impl_->Send( data, size ); -} - -void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) -{ - impl_->SendTo( remoteEndpoint, data, size ); -} - -void UdpSocket::Bind( const IpEndpointName& localEndpoint ) -{ - impl_->Bind( localEndpoint ); -} - -bool UdpSocket::IsBound() const -{ - return impl_->IsBound(); -} - -std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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(); -#ifndef WINCE - signal( SIGINT, SIG_DFL ); -#endif -} - - -class SocketReceiveMultiplexer::Implementation{ - NetworkInitializer networkInitializer_; - - std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_; - std::vector< AttachedTimerListener > timerListeners_; - - volatile bool break_; - HANDLE breakEvent_; - - double GetCurrentTimeMs() const - { -#ifndef WINCE - return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days -#else - return 0; -#endif - } - -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 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 ){ - std::size_t size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); - if( size > 0 ){ - socketListeners_[i].first->ProcessPacket( data, (int)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; -#ifndef WINCE - signal( SIGINT, InterruptSignalHandler ); -#endif - impl_->Run(); -#ifndef WINCE - signal( SIGINT, SIG_DFL ); -#endif - multiplexerInstanceToAbortWithSigInt_ = 0; -} - -void SocketReceiveMultiplexer::Break() -{ - impl_->Break(); -} - -void SocketReceiveMultiplexer::AsynchronousBreak() -{ - impl_->AsynchronousBreak(); -} - diff --git a/ext/osc/osc/MessageMappingOscPacketListener.h b/ext/osc/osc/MessageMappingOscPacketListener.h deleted file mode 100644 index bf56b530a2..0000000000 --- a/ext/osc/osc/MessageMappingOscPacketListener.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_MESSAGEMAPPINGOSCPACKETLISTENER_H -#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H - -#include -#include - -#include "OscPacketListener.h" - - - -namespace osc{ - -template< class T > -class MessageMappingOscPacketListener : public OscPacketListener{ -public: - typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&); - -protected: - void RegisterMessageFunction( const char *addressPattern, function_type f ) - { - functions_.insert( std::make_pair( addressPattern, f ) ); - } - - virtual void ProcessMessage( const osc::ReceivedMessage& m, - const IpEndpointName& remoteEndpoint ) - { - typename function_map_type::iterator i = functions_.find( m.AddressPattern() ); - if( i != functions_.end() ) - (dynamic_cast(this)->*(i->second))( m, remoteEndpoint ); - } - -private: - struct cstr_compare{ - bool operator()( const char *lhs, const char *rhs ) const - { return std::strcmp( lhs, rhs ) < 0; } - }; - - typedef std::map function_map_type; - function_map_type functions_; -}; - -} // namespace osc - -#endif /* INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H */ \ No newline at end of file diff --git a/ext/osc/osc/OscException.h b/ext/osc/osc/OscException.h deleted file mode 100644 index 73981737e0..0000000000 --- a/ext/osc/osc/OscException.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_OSCEXCEPTION_H -#define INCLUDED_OSCPACK_OSCEXCEPTION_H - -#include - -namespace osc{ - -class Exception : public std::exception { - const char *what_; - -public: - Exception() throw() {} - Exception( const Exception& src ) throw() - : std::exception( src ) - , what_( src.what_ ) {} - Exception( const char *w ) throw() - : what_( w ) {} - Exception& operator=( const Exception& src ) throw() - { what_ = src.what_; return *this; } - virtual ~Exception() throw() {} - virtual const char* what() const throw() { return what_; } -}; - -} // namespace osc - -#endif /* INCLUDED_OSCPACK_OSCEXCEPTION_H */ diff --git a/ext/osc/osc/OscHostEndianness.h b/ext/osc/osc/OscHostEndianness.h deleted file mode 100644 index 4682c473a5..0000000000 --- a/ext/osc/osc/OscHostEndianness.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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 */ - diff --git a/ext/osc/osc/OscOutboundPacketStream.cpp b/ext/osc/osc/OscOutboundPacketStream.cpp deleted file mode 100644 index b474b4f01a..0000000000 --- a/ext/osc/osc/OscOutboundPacketStream.cpp +++ /dev/null @@ -1,683 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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 "OscOutboundPacketStream.h" - -#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) -#include // for alloca -#else -//#include // alloca on Linux (also OSX) -#include // alloca on OSX and FreeBSD (and Linux?) -#endif - -#include -#include // memcpy, memmove, strcpy, strlen -#include // ptrdiff_t - -#include "OscHostEndianness.h" - -#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug -namespace std { -using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. -} -#endif - -namespace osc{ - -static void FromInt32( char *p, int32 x ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::int32 i; - char c[4]; - } u; - - u.i = x; - - p[3] = u.c[0]; - p[2] = u.c[1]; - p[1] = u.c[2]; - p[0] = u.c[3]; -#else - *reinterpret_cast(p) = x; -#endif -} - - -static void FromUInt32( char *p, uint32 x ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::uint32 i; - char c[4]; - } u; - - u.i = x; - - p[3] = u.c[0]; - p[2] = u.c[1]; - p[1] = u.c[2]; - p[0] = u.c[3]; -#else - *reinterpret_cast(p) = x; -#endif -} - - -static void FromInt64( char *p, int64 x ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::int64 i; - char c[8]; - } u; - - u.i = x; - - p[7] = u.c[0]; - p[6] = u.c[1]; - p[5] = u.c[2]; - p[4] = u.c[3]; - p[3] = u.c[4]; - p[2] = u.c[5]; - p[1] = u.c[6]; - p[0] = u.c[7]; -#else - *reinterpret_cast(p) = x; -#endif -} - - -static void FromUInt64( char *p, uint64 x ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::uint64 i; - char c[8]; - } u; - - u.i = x; - - p[7] = u.c[0]; - p[6] = u.c[1]; - p[5] = u.c[2]; - p[4] = u.c[3]; - p[3] = u.c[4]; - p[2] = u.c[5]; - p[1] = u.c[6]; - p[0] = u.c[7]; -#else - *reinterpret_cast(p) = x; -#endif -} - - -// round up to the next highest multiple of 4. unless x is already a multiple of 4 -static inline std::size_t RoundUp4( std::size_t x ) -{ - return (x + 3) & ~((std::size_t)0x03); -} - - -OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity ) - : data_( buffer ) - , end_( data_ + capacity ) - , typeTagsCurrent_( end_ ) - , messageCursor_( data_ ) - , argumentCurrent_( data_ ) - , elementSizePtr_( 0 ) - , messageIsInProgress_( false ) -{ - // sanity check integer types declared in OscTypes.h - // you'll need to fix OscTypes.h if any of these asserts fail - assert( sizeof(osc::int32) == 4 ); - assert( sizeof(osc::uint32) == 4 ); - assert( sizeof(osc::int64) == 8 ); - assert( sizeof(osc::uint64) == 8 ); -} - - -OutboundPacketStream::~OutboundPacketStream() -{ - -} - - -char *OutboundPacketStream::BeginElement( char *beginPtr ) -{ - if( elementSizePtr_ == 0 ){ - - elementSizePtr_ = reinterpret_cast(data_); - - return beginPtr; - - }else{ - // store an offset to the old element size ptr in the element size slot - // we store an offset rather than the actual pointer to be 64 bit clean. - *reinterpret_cast(beginPtr) = - (uint32)(reinterpret_cast(elementSizePtr_) - data_); - - elementSizePtr_ = reinterpret_cast(beginPtr); - - return beginPtr + 4; - } -} - - -void OutboundPacketStream::EndElement( char *endPtr ) -{ - assert( elementSizePtr_ != 0 ); - - if( elementSizePtr_ == reinterpret_cast(data_) ){ - - elementSizePtr_ = 0; - - }else{ - // while building an element, an offset to the containing element's - // size slot is stored in the elements size slot (or a ptr to data_ - // if there is no containing element). We retrieve that here - uint32 *previousElementSizePtr = - reinterpret_cast(data_ + *elementSizePtr_); - - // then we store the element size in the slot. note that the element - // size does not include the size slot, hence the - 4 below. - - std::ptrdiff_t d = endPtr - reinterpret_cast(elementSizePtr_); - // assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb - - uint32 elementSize = static_cast(d - 4); - FromUInt32( reinterpret_cast(elementSizePtr_), elementSize ); - - // finally, we reset the element size ptr to the containing element - elementSizePtr_ = previousElementSizePtr; - } -} - - -bool OutboundPacketStream::ElementSizeSlotRequired() const -{ - return (elementSizePtr_ != 0); -} - - -void OutboundPacketStream::CheckForAvailableBundleSpace() -{ - std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16; - - if( required > Capacity() ) - throw OutOfBufferMemoryException(); -} - - -void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern ) -{ - // plus 4 for at least four bytes of type tag - std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) - + RoundUp4(std::strlen(addressPattern) + 1) + 4; - - if( required > Capacity() ) - throw OutOfBufferMemoryException(); -} - - -void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength ) -{ - // plus three for extra type tag, comma and null terminator - std::size_t required = (argumentCurrent_ - data_) + argumentLength - + RoundUp4( (end_ - typeTagsCurrent_) + 3 ); - - if( required > Capacity() ) - throw OutOfBufferMemoryException(); -} - - -void OutboundPacketStream::Clear() -{ - typeTagsCurrent_ = end_; - messageCursor_ = data_; - argumentCurrent_ = data_; - elementSizePtr_ = 0; - messageIsInProgress_ = false; -} - - -std::size_t OutboundPacketStream::Capacity() const -{ - return end_ - data_; -} - - -std::size_t OutboundPacketStream::Size() const -{ - std::size_t result = argumentCurrent_ - data_; - if( IsMessageInProgress() ){ - // account for the length of the type tag string. the total type tag - // includes an initial comma, plus at least one terminating \0 - result += RoundUp4( (end_ - typeTagsCurrent_) + 2 ); - } - - return result; -} - - -const char *OutboundPacketStream::Data() const -{ - return data_; -} - - -bool OutboundPacketStream::IsReady() const -{ - return (!IsMessageInProgress() && !IsBundleInProgress()); -} - - -bool OutboundPacketStream::IsMessageInProgress() const -{ - return messageIsInProgress_; -} - - -bool OutboundPacketStream::IsBundleInProgress() const -{ - return (elementSizePtr_ != 0); -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs ) -{ - if( IsMessageInProgress() ) - throw MessageInProgressException(); - - CheckForAvailableBundleSpace(); - - messageCursor_ = BeginElement( messageCursor_ ); - - std::memcpy( messageCursor_, "#bundle\0", 8 ); - FromUInt64( messageCursor_ + 8, rhs.timeTag ); - - messageCursor_ += 16; - argumentCurrent_ = messageCursor_; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs ) -{ - (void) rhs; - - if( !IsBundleInProgress() ) - throw BundleNotInProgressException(); - if( IsMessageInProgress() ) - throw MessageInProgressException(); - - EndElement( messageCursor_ ); - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs ) -{ - if( IsMessageInProgress() ) - throw MessageInProgressException(); - - CheckForAvailableMessageSpace( rhs.addressPattern ); - - messageCursor_ = BeginElement( messageCursor_ ); - - std::strcpy( messageCursor_, rhs.addressPattern ); - std::size_t rhsLength = std::strlen(rhs.addressPattern); - messageCursor_ += rhsLength + 1; - - // zero pad to 4-byte boundary - std::size_t i = rhsLength + 1; - while( i & 0x3 ){ - *messageCursor_++ = '\0'; - ++i; - } - - argumentCurrent_ = messageCursor_; - typeTagsCurrent_ = end_; - - messageIsInProgress_ = true; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs ) -{ - (void) rhs; - - if( !IsMessageInProgress() ) - throw MessageNotInProgressException(); - - std::size_t typeTagsCount = end_ - typeTagsCurrent_; - - if( typeTagsCount ){ - - char *tempTypeTags = (char*)alloca(typeTagsCount); - std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount ); - - // slot size includes comma and null terminator - std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 ); - - std::size_t argumentsSize = argumentCurrent_ - messageCursor_; - - std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize ); - - messageCursor_[0] = ','; - // copy type tags in reverse (really forward) order - for( std::size_t i=0; i < typeTagsCount; ++i ) - messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ]; - - char *p = messageCursor_ + 1 + typeTagsCount; - for( std::size_t i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i ) - *p++ = '\0'; - - typeTagsCurrent_ = end_; - - // advance messageCursor_ for next message - messageCursor_ += typeTagSlotSize + argumentsSize; - - }else{ - // send an empty type tags string - std::memcpy( messageCursor_, ",\0\0\0", 4 ); - - // advance messageCursor_ for next message - messageCursor_ += 4; - } - - argumentCurrent_ = messageCursor_; - - EndElement( messageCursor_ ); - - messageIsInProgress_ = false; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs ) -{ - CheckForAvailableArgumentSpace(0); - - *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG); - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs ) -{ - (void) rhs; - CheckForAvailableArgumentSpace(0); - - *(--typeTagsCurrent_) = NIL_TYPE_TAG; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs ) -{ - (void) rhs; - CheckForAvailableArgumentSpace(0); - - *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs ) -{ - CheckForAvailableArgumentSpace(4); - - *(--typeTagsCurrent_) = INT32_TYPE_TAG; - FromInt32( argumentCurrent_, rhs ); - argumentCurrent_ += 4; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( float rhs ) -{ - CheckForAvailableArgumentSpace(4); - - *(--typeTagsCurrent_) = FLOAT_TYPE_TAG; - -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - float f; - char c[4]; - } u; - - u.f = rhs; - - argumentCurrent_[3] = u.c[0]; - argumentCurrent_[2] = u.c[1]; - argumentCurrent_[1] = u.c[2]; - argumentCurrent_[0] = u.c[3]; -#else - *reinterpret_cast(argumentCurrent_) = rhs; -#endif - - argumentCurrent_ += 4; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( char rhs ) -{ - CheckForAvailableArgumentSpace(4); - - *(--typeTagsCurrent_) = CHAR_TYPE_TAG; - FromInt32( argumentCurrent_, rhs ); - argumentCurrent_ += 4; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs ) -{ - CheckForAvailableArgumentSpace(4); - - *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG; - FromUInt32( argumentCurrent_, rhs ); - argumentCurrent_ += 4; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs ) -{ - CheckForAvailableArgumentSpace(4); - - *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG; - FromUInt32( argumentCurrent_, rhs ); - argumentCurrent_ += 4; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs ) -{ - CheckForAvailableArgumentSpace(8); - - *(--typeTagsCurrent_) = INT64_TYPE_TAG; - FromInt64( argumentCurrent_, rhs ); - argumentCurrent_ += 8; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs ) -{ - CheckForAvailableArgumentSpace(8); - - *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG; - FromUInt64( argumentCurrent_, rhs ); - argumentCurrent_ += 8; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( double rhs ) -{ - CheckForAvailableArgumentSpace(8); - - *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG; - -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - double f; - char c[8]; - } u; - - u.f = rhs; - - argumentCurrent_[7] = u.c[0]; - argumentCurrent_[6] = u.c[1]; - argumentCurrent_[5] = u.c[2]; - argumentCurrent_[4] = u.c[3]; - argumentCurrent_[3] = u.c[4]; - argumentCurrent_[2] = u.c[5]; - argumentCurrent_[1] = u.c[6]; - argumentCurrent_[0] = u.c[7]; -#else - *reinterpret_cast(argumentCurrent_) = rhs; -#endif - - argumentCurrent_ += 8; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) -{ - CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); - - *(--typeTagsCurrent_) = STRING_TYPE_TAG; - std::strcpy( argumentCurrent_, rhs ); - std::size_t rhsLength = std::strlen(rhs); - argumentCurrent_ += rhsLength + 1; - - // zero pad to 4-byte boundary - std::size_t i = rhsLength + 1; - while( i & 0x3 ){ - *argumentCurrent_++ = '\0'; - ++i; - } - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs ) -{ - CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); - - *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG; - std::strcpy( argumentCurrent_, rhs ); - std::size_t rhsLength = std::strlen(rhs); - argumentCurrent_ += rhsLength + 1; - - // zero pad to 4-byte boundary - std::size_t i = rhsLength + 1; - while( i & 0x3 ){ - *argumentCurrent_++ = '\0'; - ++i; - } - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs ) -{ - CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) ); - - *(--typeTagsCurrent_) = BLOB_TYPE_TAG; - FromUInt32( argumentCurrent_, rhs.size ); - argumentCurrent_ += 4; - - std::memcpy( argumentCurrent_, rhs.data, rhs.size ); - argumentCurrent_ += rhs.size; - - // zero pad to 4-byte boundary - unsigned long i = rhs.size; - while( i & 0x3 ){ - *argumentCurrent_++ = '\0'; - ++i; - } - - return *this; -} - -OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs ) -{ - (void) rhs; - CheckForAvailableArgumentSpace(0); - - *(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG; - - return *this; -} - -OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs ) -{ - (void) rhs; - CheckForAvailableArgumentSpace(0); - - *(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG; - - return *this; -} - -} // namespace osc - - diff --git a/ext/osc/osc/OscOutboundPacketStream.h b/ext/osc/osc/OscOutboundPacketStream.h deleted file mode 100644 index d0afe95421..0000000000 --- a/ext/osc/osc/OscOutboundPacketStream.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_OSCOUTBOUNDPACKETSTREAM_H -#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H - -#include // size_t - -#include "OscTypes.h" -#include "OscException.h" - - -namespace osc{ - -class OutOfBufferMemoryException : public Exception{ -public: - OutOfBufferMemoryException( const char *w="out of buffer memory" ) - : Exception( w ) {} -}; - -class BundleNotInProgressException : public Exception{ -public: - BundleNotInProgressException( - const char *w="call to EndBundle when bundle is not in progress" ) - : Exception( w ) {} -}; - -class MessageInProgressException : public Exception{ -public: - MessageInProgressException( - const char *w="opening or closing bundle or message while message is in progress" ) - : Exception( w ) {} -}; - -class MessageNotInProgressException : public Exception{ -public: - MessageNotInProgressException( - const char *w="call to EndMessage when message is not in progress" ) - : Exception( w ) {} -}; - - -class OutboundPacketStream{ -public: - OutboundPacketStream() = default; - OutboundPacketStream( char *buffer, std::size_t capacity ); - ~OutboundPacketStream(); - - void Clear(); - - std::size_t Capacity() const; - - // invariant: size() is valid even while building a message. - std::size_t Size() const; - - const char *Data() const; - - // indicates that all messages have been closed with a matching EndMessage - // and all bundles have been closed with a matching EndBundle - bool IsReady() const; - - bool IsMessageInProgress() const; - bool IsBundleInProgress() const; - - OutboundPacketStream& operator<<( const BundleInitiator& rhs ); - OutboundPacketStream& operator<<( const BundleTerminator& rhs ); - - OutboundPacketStream& operator<<( const BeginMessage& rhs ); - OutboundPacketStream& operator<<( const MessageTerminator& rhs ); - - OutboundPacketStream& operator<<( bool rhs ); - OutboundPacketStream& operator<<( const NilType& rhs ); - OutboundPacketStream& operator<<( const InfinitumType& rhs ); - OutboundPacketStream& operator<<( int32 rhs ); - -#if !(defined(__x86_64__) || defined(_M_X64)) - OutboundPacketStream& operator<<( int rhs ) - { *this << (int32)rhs; return *this; } -#endif - - OutboundPacketStream& operator<<( float rhs ); - OutboundPacketStream& operator<<( char rhs ); - OutboundPacketStream& operator<<( const RgbaColor& rhs ); - OutboundPacketStream& operator<<( const MidiMessage& rhs ); - OutboundPacketStream& operator<<( int64 rhs ); - OutboundPacketStream& operator<<( const TimeTag& rhs ); - OutboundPacketStream& operator<<( double rhs ); - OutboundPacketStream& operator<<( const char* rhs ); - OutboundPacketStream& operator<<( const Symbol& rhs ); - OutboundPacketStream& operator<<( const Blob& rhs ); - - OutboundPacketStream& operator<<( const ArrayInitiator& rhs ); - OutboundPacketStream& operator<<( const ArrayTerminator& rhs ); - -private: - - char *BeginElement( char *beginPtr ); - void EndElement( char *endPtr ); - - bool ElementSizeSlotRequired() const; - void CheckForAvailableBundleSpace(); - void CheckForAvailableMessageSpace( const char *addressPattern ); - void CheckForAvailableArgumentSpace( std::size_t argumentLength ); - - char *data_; - char *end_; - - char *typeTagsCurrent_; // stored in reverse order - char *messageCursor_; - char *argumentCurrent_; - - // 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 */ diff --git a/ext/osc/osc/OscPacketListener.h b/ext/osc/osc/OscPacketListener.h deleted file mode 100644 index 472cb1066f..0000000000 --- a/ext/osc/osc/OscPacketListener.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_OSCPACKETLISTENER_H -#define INCLUDED_OSCPACK_OSCPACKETLISTENER_H - -#include "OscReceivedElements.h" -#include "../ip/PacketListener.h" - - -namespace osc{ - -class OscPacketListener : public PacketListener{ -protected: - virtual void ProcessBundle( const osc::ReceivedBundle& b, - const IpEndpointName& remoteEndpoint ) - { - // ignore bundle time tag for now - - for( ReceivedBundle::const_iterator i = b.ElementsBegin(); - i != b.ElementsEnd(); ++i ){ - if( i->IsBundle() ) - ProcessBundle( ReceivedBundle(*i), remoteEndpoint ); - else - ProcessMessage( ReceivedMessage(*i), remoteEndpoint ); - } - } - - virtual void ProcessMessage( const osc::ReceivedMessage& m, - const IpEndpointName& remoteEndpoint ) = 0; - -public: - virtual void ProcessPacket( const char *data, int size, - const IpEndpointName& remoteEndpoint ) - { - osc::ReceivedPacket p( data, size ); - if( p.IsBundle() ) - ProcessBundle( ReceivedBundle(p), remoteEndpoint ); - else - ProcessMessage( ReceivedMessage(p), remoteEndpoint ); - } -}; - -} // namespace osc - -#endif /* INCLUDED_OSCPACK_OSCPACKETLISTENER_H */ diff --git a/ext/osc/osc/OscPrintReceivedElements.cpp b/ext/osc/osc/OscPrintReceivedElements.cpp deleted file mode 100644 index bc1689bc1d..0000000000 --- a/ext/osc/osc/OscPrintReceivedElements.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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 "OscPrintReceivedElements.h" - -#include -#include -#include -#include - -#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug -namespace std { -using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. -} -#endif - -namespace osc{ - - -std::ostream& operator<<( std::ostream & os, - const ReceivedMessageArgument& arg ) -{ - switch( arg.TypeTag() ){ - case TRUE_TYPE_TAG: - os << "bool:true"; - break; - - case FALSE_TYPE_TAG: - os << "bool:false"; - break; - - case NIL_TYPE_TAG: - os << "(Nil)"; - break; - - case INFINITUM_TYPE_TAG: - os << "(Infinitum)"; - break; - - case INT32_TYPE_TAG: - os << "int32:" << arg.AsInt32Unchecked(); - break; - - case FLOAT_TYPE_TAG: - os << "float32:" << arg.AsFloatUnchecked(); - break; - - case CHAR_TYPE_TAG: - { - char s[2] = {0}; - s[0] = arg.AsCharUnchecked(); - os << "char:'" << s << "'"; - } - break; - - case RGBA_COLOR_TYPE_TAG: - { - uint32 color = arg.AsRgbaColorUnchecked(); - - os << "RGBA:0x" - << std::hex << std::setfill('0') - << std::setw(2) << (int)((color>>24) & 0xFF) - << std::setw(2) << (int)((color>>16) & 0xFF) - << std::setw(2) << (int)((color>>8) & 0xFF) - << std::setw(2) << (int)(color & 0xFF) - << std::setfill(' '); - os.unsetf(std::ios::basefield); - } - break; - - case MIDI_MESSAGE_TYPE_TAG: - { - uint32 m = arg.AsMidiMessageUnchecked(); - os << "midi (port, status, data1, data2):<<" - << std::hex << std::setfill('0') - << "0x" << std::setw(2) << (int)((m>>24) & 0xFF) - << " 0x" << std::setw(2) << (int)((m>>16) & 0xFF) - << " 0x" << std::setw(2) << (int)((m>>8) & 0xFF) - << " 0x" << std::setw(2) << (int)(m & 0xFF) - << std::setfill(' ') << ">>"; - os.unsetf(std::ios::basefield); - } - break; - - case INT64_TYPE_TAG: - os << "int64:" << arg.AsInt64Unchecked(); - break; - - case TIME_TAG_TYPE_TAG: - { - os << "OSC-timetag:" << arg.AsTimeTagUnchecked() << " "; - - std::time_t t = - (unsigned long)( arg.AsTimeTagUnchecked() >> 32 ); - - const char *timeString = std::ctime( &t ); - size_t len = std::strlen( timeString ); - - // -1 to omit trailing newline from string returned by ctime() - if( len > 1 ) - os.write( timeString, len - 1 ); - } - break; - - case DOUBLE_TYPE_TAG: - os << "double:" << arg.AsDoubleUnchecked(); - break; - - case STRING_TYPE_TAG: - os << "OSC-string:`" << arg.AsStringUnchecked() << "'"; - break; - - case SYMBOL_TYPE_TAG: - os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'"; - break; - - case BLOB_TYPE_TAG: - { - const void *data; - osc_bundle_element_size_t size; - arg.AsBlobUnchecked( data, size ); - os << "OSC-blob:<<" << std::hex << std::setfill('0'); - unsigned char *p = (unsigned char*)data; - for( osc_bundle_element_size_t i = 0; i < size; ++i ){ - os << "0x" << std::setw(2) << int(p[i]); - if( i != size-1 ) - os << ' '; - } - os.unsetf(std::ios::basefield); - os << ">>" << std::setfill(' '); - } - break; - - case ARRAY_BEGIN_TYPE_TAG: - os << "["; - break; - - case ARRAY_END_TYPE_TAG: - os << "]"; - break; - - default: - os << "unknown"; - } - - return os; -} - - -std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ) -{ - os << "["; - if( m.AddressPatternIsUInt32() ) - os << m.AddressPatternAsUInt32(); - else - os << m.AddressPattern(); - - bool first = true; - for( ReceivedMessage::const_iterator i = m.ArgumentsBegin(); - i != m.ArgumentsEnd(); ++i ){ - if( first ){ - os << " "; - first = false; - }else{ - os << ", "; - } - - os << *i; - } - - os << "]"; - - return os; -} - - -std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ) -{ - static int indent = 0; - - for( int j=0; j < indent; ++j ) - os << " "; - os << "{ ( "; - if( b.TimeTag() == 1 ) - os << "immediate"; - else - os << b.TimeTag(); - os << " )\n"; - - ++indent; - - for( ReceivedBundle::const_iterator i = b.ElementsBegin(); - i != b.ElementsEnd(); ++i ){ - if( i->IsBundle() ){ - ReceivedBundle b(*i); - os << b << "\n"; - }else{ - ReceivedMessage m(*i); - for( int j=0; j < indent; ++j ) - os << " "; - os << m << "\n"; - } - } - - --indent; - - for( int j=0; j < indent; ++j ) - os << " "; - 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 diff --git a/ext/osc/osc/OscPrintReceivedElements.h b/ext/osc/osc/OscPrintReceivedElements.h deleted file mode 100644 index 8d71391f0c..0000000000 --- a/ext/osc/osc/OscPrintReceivedElements.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_OSCPRINTRECEIVEDELEMENTS_H -#define INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H - -#include - -#include "OscReceivedElements.h" - - -namespace osc{ - -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 ); -std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ); - -} // namespace osc - -#endif /* INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H */ diff --git a/ext/osc/osc/OscReceivedElements.cpp b/ext/osc/osc/OscReceivedElements.cpp deleted file mode 100644 index 1d57d3740a..0000000000 --- a/ext/osc/osc/OscReceivedElements.cpp +++ /dev/null @@ -1,796 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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 // 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 - diff --git a/ext/osc/osc/OscReceivedElements.h b/ext/osc/osc/OscReceivedElements.h deleted file mode 100644 index b6205f3168..0000000000 --- a/ext/osc/osc/OscReceivedElements.h +++ /dev/null @@ -1,548 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_OSCRECEIVEDELEMENTS_H -#define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H - -#include -#include -#include // size_t - -#include "OscTypes.h" -#include "OscException.h" - - -namespace osc{ - - -class MalformedPacketException : public Exception{ -public: - MalformedPacketException( const char *w="malformed packet" ) - : Exception( w ) {} -}; - -class MalformedMessageException : public Exception{ -public: - MalformedMessageException( const char *w="malformed message" ) - : Exception( w ) {} -}; - -class MalformedBundleException : public Exception{ -public: - MalformedBundleException( const char *w="malformed bundle" ) - : Exception( w ) {} -}; - -class WrongArgumentTypeException : public Exception{ -public: - WrongArgumentTypeException( const char *w="wrong argument type" ) - : Exception( w ) {} -}; - -class MissingArgumentException : public Exception{ -public: - MissingArgumentException( const char *w="missing argument" ) - : Exception( w ) {} -}; - -class ExcessArgumentException : public Exception{ -public: - ExcessArgumentException( const char *w="too many arguments" ) - : Exception( w ) {} -}; - - -class ReceivedPacket{ -public: - // Although the OSC spec is not entirely clear on this, we only support - // packets up to 0x7FFFFFFC bytes long (the maximum 4-byte aligned value - // representable by an int32). An exception will be raised if you pass a - // larger value to the ReceivedPacket() constructor. - - ReceivedPacket( const char *contents, osc_bundle_element_size_t size ) - : contents_( contents ) - , size_( ValidateSize(size) ) {} - - ReceivedPacket( const char *contents, std::size_t size ) - : contents_( contents ) - , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} - -#if !(defined(__x86_64__) || defined(_M_X64)) - ReceivedPacket( const char *contents, int size ) - : contents_( contents ) - , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} -#endif - - bool IsMessage() const { return !IsBundle(); } - bool IsBundle() const; - - osc_bundle_element_size_t Size() const { return size_; } - const char *Contents() const { return contents_; } - -private: - const char *contents_; - osc_bundle_element_size_t size_; - - static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size ) - { - // sanity check integer types declared in OscTypes.h - // you'll need to fix OscTypes.h if any of these asserts fail - assert( sizeof(osc::int32) == 4 ); - assert( sizeof(osc::uint32) == 4 ); - assert( sizeof(osc::int64) == 8 ); - assert( sizeof(osc::uint64) == 8 ); - - if( !IsValidElementSizeValue(size) ) - throw MalformedPacketException( "invalid packet size" ); - - if( size == 0 ) - throw MalformedPacketException( "zero length elements not permitted" ); - - if( !IsMultipleOf4(size) ) - throw MalformedPacketException( "element size must be multiple of four" ); - - return size; - } -}; - - -class ReceivedBundleElement{ -public: - ReceivedBundleElement( const char *sizePtr ) - : sizePtr_( sizePtr ) {} - - friend class ReceivedBundleElementIterator; - - bool IsMessage() const { return !IsBundle(); } - bool IsBundle() const; - - osc_bundle_element_size_t Size() const; - const char *Contents() const { return sizePtr_ + osc::OSC_SIZEOF_INT32; } - -private: - const char *sizePtr_; -}; - - -class ReceivedBundleElementIterator{ -public: - ReceivedBundleElementIterator( const char *sizePtr ) - : value_( sizePtr ) {} - - ReceivedBundleElementIterator operator++() - { - Advance(); - return *this; - } - - ReceivedBundleElementIterator operator++(int) - { - ReceivedBundleElementIterator old( *this ); - Advance(); - return old; - } - - const ReceivedBundleElement& operator*() const { return value_; } - - const ReceivedBundleElement* operator->() const { return &value_; } - - friend bool operator==(const ReceivedBundleElementIterator& lhs, - const ReceivedBundleElementIterator& rhs ); - -private: - ReceivedBundleElement value_; - - void Advance() { value_.sizePtr_ = value_.Contents() + value_.Size(); } - - bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const - { - return value_.sizePtr_ == rhs.value_.sizePtr_; - } -}; - -inline bool operator==(const ReceivedBundleElementIterator& lhs, - const ReceivedBundleElementIterator& rhs ) -{ - return lhs.IsEqualTo( rhs ); -} - -inline bool operator!=(const ReceivedBundleElementIterator& lhs, - const ReceivedBundleElementIterator& rhs ) -{ - return !( lhs == rhs ); -} - - -class ReceivedMessageArgument{ -public: - ReceivedMessageArgument( const char *typeTagPtr, const char *argumentPtr ) - : typeTagPtr_( typeTagPtr ) - , argumentPtr_( argumentPtr ) {} - - friend class ReceivedMessageArgumentIterator; - - char TypeTag() const { return *typeTagPtr_; } - - // the unchecked methods below don't check whether the argument actually - // is of the specified type. they should only be used if you've already - // checked the type tag or the associated IsType() method. - - bool IsBool() const - { return *typeTagPtr_ == TRUE_TYPE_TAG || *typeTagPtr_ == FALSE_TYPE_TAG; } - bool AsBool() const; - bool AsBoolUnchecked() const; - - bool IsNil() const { return *typeTagPtr_ == NIL_TYPE_TAG; } - bool IsInfinitum() const { return *typeTagPtr_ == INFINITUM_TYPE_TAG; } - - bool IsInt32() const { return *typeTagPtr_ == INT32_TYPE_TAG; } - int32 AsInt32() const; - int32 AsInt32Unchecked() const; - - bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; } - float AsFloat() const; - float AsFloatUnchecked() const; - - bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; } - char AsChar() const; - char AsCharUnchecked() const; - - bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; } - uint32 AsRgbaColor() const; - uint32 AsRgbaColorUnchecked() const; - - bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; } - uint32 AsMidiMessage() const; - uint32 AsMidiMessageUnchecked() const; - - bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; } - int64 AsInt64() const; - int64 AsInt64Unchecked() const; - - bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; } - uint64 AsTimeTag() const; - uint64 AsTimeTagUnchecked() const; - - bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; } - double AsDouble() const; - double AsDoubleUnchecked() const; - - bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; } - const char* AsString() const; - const char* AsStringUnchecked() const { return argumentPtr_; } - - bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; } - const char* AsSymbol() const; - const char* AsSymbolUnchecked() const { return argumentPtr_; } - - bool IsBlob() const { return *typeTagPtr_ == BLOB_TYPE_TAG; } - void AsBlob( const void*& data, osc_bundle_element_size_t& size ) const; - void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const; - - bool IsArrayBegin() const { return *typeTagPtr_ == ARRAY_BEGIN_TYPE_TAG; } - bool IsArrayEnd() const { return *typeTagPtr_ == ARRAY_END_TYPE_TAG; } - // Calculate the number of top-level items in the array. Nested arrays count as one item. - // Only valid at array start. Will throw an exception if IsArrayStart() == false. - std::size_t ComputeArrayItemCount() const; - -private: - const char *typeTagPtr_; - const char *argumentPtr_; -}; - - -class ReceivedMessageArgumentIterator{ -public: - ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments ) - : value_( typeTags, arguments ) {} - - ReceivedMessageArgumentIterator operator++() - { - Advance(); - return *this; - } - - ReceivedMessageArgumentIterator operator++(int) - { - ReceivedMessageArgumentIterator old( *this ); - Advance(); - return old; - } - - const ReceivedMessageArgument& operator*() const { return value_; } - - const ReceivedMessageArgument* operator->() const { return &value_; } - - friend bool operator==(const ReceivedMessageArgumentIterator& lhs, - const ReceivedMessageArgumentIterator& rhs ); - -private: - ReceivedMessageArgument value_; - - void Advance(); - - bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const - { - return value_.typeTagPtr_ == rhs.value_.typeTagPtr_; - } -}; - -inline bool operator==(const ReceivedMessageArgumentIterator& lhs, - const ReceivedMessageArgumentIterator& rhs ) -{ - return lhs.IsEqualTo( rhs ); -} - -inline bool operator!=(const ReceivedMessageArgumentIterator& lhs, - const ReceivedMessageArgumentIterator& rhs ) -{ - return !( lhs == rhs ); -} - - -class ReceivedMessageArgumentStream{ - friend class ReceivedMessage; - ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin, - const ReceivedMessageArgumentIterator& end ) - : p_( begin ) - , end_( end ) {} - - ReceivedMessageArgumentIterator p_, end_; - -public: - - // end of stream - bool Eos() const { return p_ == end_; } - - ReceivedMessageArgumentStream& operator>>( bool& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsBool(); - return *this; - } - - // not sure if it would be useful to stream Nil and Infinitum - // for now it's not possible - // same goes for array boundaries - - ReceivedMessageArgumentStream& operator>>( int32& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsInt32(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( float& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsFloat(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( char& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsChar(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs.value = (*p_++).AsRgbaColor(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs.value = (*p_++).AsMidiMessage(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( int64& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsInt64(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( TimeTag& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs.value = (*p_++).AsTimeTag(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( double& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsDouble(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( Blob& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - (*p_++).AsBlob( rhs.data, rhs.size ); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( const char*& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsString(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( Symbol& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs.value = (*p_++).AsSymbol(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) - { - (void) rhs; // suppress unused parameter warning - - if( !Eos() ) - throw ExcessArgumentException(); - - return *this; - } -}; - - -class ReceivedMessage{ - void Init( const char *bundle, osc_bundle_element_size_t size ); -public: - explicit ReceivedMessage( const ReceivedPacket& packet ); - explicit ReceivedMessage( const ReceivedBundleElement& bundleElement ); - - const char *AddressPattern() const { return addressPattern_; } - - // Support for non-standard SuperCollider integer address patterns: - bool AddressPatternIsUInt32() const; - uint32 AddressPatternAsUInt32() const; - - uint32 ArgumentCount() const { return static_cast(typeTagsEnd_ - typeTagsBegin_); } - - const char *TypeTags() const { return typeTagsBegin_; } - - - typedef ReceivedMessageArgumentIterator const_iterator; - - ReceivedMessageArgumentIterator ArgumentsBegin() const - { - return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ ); - } - - ReceivedMessageArgumentIterator ArgumentsEnd() const - { - return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 ); - } - - ReceivedMessageArgumentStream ArgumentStream() const - { - return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() ); - } - -private: - const char *addressPattern_; - const char *typeTagsBegin_; - const char *typeTagsEnd_; - const char *arguments_; -}; - - -class ReceivedBundle{ - void Init( const char *message, osc_bundle_element_size_t size ); -public: - explicit ReceivedBundle( const ReceivedPacket& packet ); - explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); - - uint64 TimeTag() const; - - uint32 ElementCount() const { return elementCount_; } - - typedef ReceivedBundleElementIterator const_iterator; - - ReceivedBundleElementIterator ElementsBegin() const - { - return ReceivedBundleElementIterator( timeTag_ + 8 ); - } - - ReceivedBundleElementIterator ElementsEnd() const - { - return ReceivedBundleElementIterator( end_ ); - } - -private: - const char *timeTag_; - const char *end_; - uint32 elementCount_; -}; - - -} // namespace osc - - -#endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */ diff --git a/ext/osc/osc/OscTypes.cpp b/ext/osc/osc/OscTypes.cpp deleted file mode 100644 index 444a9fed48..0000000000 --- a/ext/osc/osc/OscTypes.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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 "OscTypes.h" - -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 diff --git a/ext/osc/osc/OscTypes.h b/ext/osc/osc/OscTypes.h deleted file mode 100644 index 610020182e..0000000000 --- a/ext/osc/osc/OscTypes.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - 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_OSCTYPES_H -#define INCLUDED_OSCPACK_OSCTYPES_H - - -namespace osc{ - -// basic types - -#if defined(__BORLANDC__) || defined(_MSC_VER) - -typedef __int64 int64; -typedef unsigned __int64 uint64; - -#elif defined(__x86_64__) || defined(_M_X64) - -typedef long int64; -typedef unsigned long uint64; - -#else - -typedef long long int64; -typedef unsigned long long uint64; - -#endif - - - -#if defined(__x86_64__) || defined(_M_X64) - -typedef signed int int32; -typedef unsigned int uint32; - -#else - -typedef signed long int32; -typedef unsigned long uint32; - -#endif - - -enum ValueTypeSizes{ - OSC_SIZEOF_INT32 = 4, - OSC_SIZEOF_UINT32 = 4, - OSC_SIZEOF_INT64 = 8, - OSC_SIZEOF_UINT64 = 8, -}; - - -// osc_bundle_element_size_t is used for the size of bundle elements and blobs -// the OSC spec specifies these as int32 (signed) but we ensure that they -// are always positive since negative field sizes make no sense. - -typedef int32 osc_bundle_element_size_t; - -enum { - OSC_INT32_MAX = 0x7FFFFFFF, - - // Element sizes are specified to be int32, and are always rounded up to nearest - // multiple of 4. Therefore their values can't be greater than 0x7FFFFFFC. - OSC_BUNDLE_ELEMENT_SIZE_MAX = 0x7FFFFFFC -}; - - -inline bool IsValidElementSizeValue( osc_bundle_element_size_t x ) -{ - // sizes may not be negative or exceed OSC_BUNDLE_ELEMENT_SIZE_MAX - return x >= 0 && x <= OSC_BUNDLE_ELEMENT_SIZE_MAX; -} - - -inline bool IsMultipleOf4( osc_bundle_element_size_t x ) -{ - return (x & ((osc_bundle_element_size_t)0x03)) == 0; -} - - -enum TypeTagValues { - TRUE_TYPE_TAG = 'T', - FALSE_TYPE_TAG = 'F', - NIL_TYPE_TAG = 'N', - INFINITUM_TYPE_TAG = 'I', - INT32_TYPE_TAG = 'i', - FLOAT_TYPE_TAG = 'f', - CHAR_TYPE_TAG = 'c', - RGBA_COLOR_TYPE_TAG = 'r', - MIDI_MESSAGE_TYPE_TAG = 'm', - INT64_TYPE_TAG = 'h', - TIME_TAG_TYPE_TAG = 't', - DOUBLE_TYPE_TAG = 'd', - STRING_TYPE_TAG = 's', - SYMBOL_TYPE_TAG = 'S', - BLOB_TYPE_TAG = 'b', - ARRAY_BEGIN_TYPE_TAG = '[', - ARRAY_END_TYPE_TAG = ']' -}; - - - -// i/o manipulators used for streaming interfaces - -struct BundleInitiator{ - explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {} - uint64 timeTag; -}; - -extern BundleInitiator BeginBundleImmediate; - -inline BundleInitiator BeginBundle( uint64 timeTag=1 ) -{ - return BundleInitiator(timeTag); -} - - -struct BundleTerminator{ -}; - -extern BundleTerminator EndBundle; - -struct BeginMessage{ - explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {} - const char *addressPattern; -}; - -struct MessageTerminator{ -}; - -extern MessageTerminator EndMessage; - - -// osc specific types. they are defined as structs so they can be used -// as separately identifiable types with the streaming operators. - -struct NilType{ -}; - -extern NilType OscNil; - -#ifndef _OBJC_OBJC_H_ -extern NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead -#endif - -struct InfinitumType{ -}; - -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 */