Move (outdated) samples to another repo

This commit is contained in:
monsieurgustav
2019-04-08 17:54:04 +02:00
parent cb697cb9df
commit 3308850d8a
49 changed files with 0 additions and 4911 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +0,0 @@
[EditoronlyBP]
bAllowClassAndBlueprintPinMatching=true
bReplaceBlueprintWithClass=true
bDontLoadBlueprintOutsideEditor=true
bBlueprintIsNotBlueprintType=true
-12
View File
@@ -1,12 +0,0 @@
[URL]
[/Script/HardwareTargeting.HardwareTargetingSettings]
TargetedHardwareClass=Desktop
AppliedTargetedHardwareClass=Desktop
DefaultGraphicsPerformance=Maximum
AppliedDefaultGraphicsPerformance=Maximum
[/Script/EngineSettings.GameMapsSettings]
EditorStartupMap=/Game/Map.Map
GameDefaultMap=/Game/Map.Map
-2
View File
@@ -1,2 +0,0 @@
[/Script/EngineSettings.GeneralProjectSettings]
ProjectID=316644CF469FFDAC26DC92ADB05D7359
Binary file not shown.
Binary file not shown.
-13
View File
@@ -1,13 +0,0 @@
{
"FileVersion": 3,
"EngineAssociation": "4.17",
"Category": "",
"Description": "",
"Modules": [
{
"Name": "OscDemo",
"Type": "Runtime",
"LoadingPhase": "Default"
}
]
}
-24
View File
@@ -1,24 +0,0 @@
{
"FileVersion" : 3,
"FriendlyName" : "OSC",
"Version" : 1,
"VersionName" : "1.0",
"CreatedBy" : "Guillaume Buisson",
"CreatedByURL" : "http://guillaume.io",
"Description" : "",
"Category" : "OSC",
"EnabledByDefault" : true,
"Modules" :
[
{
"Name" : "OSC",
"Type" : "Runtime",
"LoadingPhase" : "PreDefault",
"BlacklistPlatforms" : [ "HTML5" ]
}
],
"CanContainContent" : false
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

@@ -1,53 +0,0 @@
namespace UnrealBuildTool.Rules
{
public class OSC : ModuleRules
{
public OSC(ReadOnlyTargetRules Target) : base(Target)
{
PublicDependencyModuleNames.AddRange(
new string[]
{
"Networking",
}
);
PrivateDependencyModuleNames.AddRange(
new string[] {
"Core",
"CoreUObject",
"Engine",
"Sockets",
"InputCore",
"Slate",
"SlateCore",
}
);
PrivateIncludePathModuleNames.AddRange(
new string[] {
"Settings",
}
);
PrivateIncludePaths.AddRange(
new string[] {
"OSC/Private",
"OSC/Private/Common",
"OSC/Private/Receive",
"OSC/Private/Send",
}
);
if (Target.Type == TargetRules.TargetType.Editor)
{
Definitions.Add("OSC_EDITOR_BUILD=1");
PrivateDependencyModuleNames.Add("UnrealEd");
}
else
{
Definitions.Add("OSC_EDITOR_BUILD=0");
}
}
}
}
@@ -1,228 +0,0 @@
#pragma once
#include "OscDataElemStruct.generated.h"
USTRUCT(BlueprintType)
struct FOscDataElemStruct
{
GENERATED_USTRUCT_BODY()
enum
{
FLOAT = 0,
INT = 1,
BOOL = 2,
STRING = 3,
BLOB = 4,
};
public:
FOscDataElemStruct() : Type(0), Data(0)
{
}
void SetFloat(double value)
{
static_assert(sizeof(value) <= sizeof(Data), "Too short to hold the float value.");
Type = FLOAT;
Data = *reinterpret_cast<int64 *>(&value);
check(value == AsFloatValue());
}
double AsFloatValue() const
{
check(IsFloat());
return *reinterpret_cast<const double *>(&Data);
}
bool IsFloat() const
{
return Type == FLOAT;
}
//-------------------------------------------------------------------------
void SetInt(int64 value)
{
static_assert(sizeof(value) <= sizeof(Data), "Too short to hold the integer value.");
Type = INT;
Data = value;
check(value == AsIntValue());
}
int64 AsIntValue() const
{
check(IsInt());
return Data;
}
bool IsInt() const
{
return Type == INT;
}
//-------------------------------------------------------------------------
void SetBool(bool value)
{
static_assert(sizeof(value) <= sizeof(Data), "Too short to hold the bool value.");
Type = BOOL;
Data = value;
check(value == AsBoolValue());
}
bool AsBoolValue() const
{
check(IsBool());
return Data != 0;
}
bool IsBool() const
{
return Type == BOOL;
}
//-------------------------------------------------------------------------
void SetString(FName value)
{
static_assert(sizeof(FMinimalName) <= sizeof(Data), "Too short to hold the string value.");
const auto mininal = NameToMinimalName(value);
Data = *reinterpret_cast<const int64*>(&mininal);
Type = STRING;
check(value == AsStringValue());
}
FName AsStringValue() const
{
check(IsString());
return MinimalNameToName(*reinterpret_cast<const FMinimalName *>(&Data));
}
bool IsString() const
{
return Type == STRING;
}
//-------------------------------------------------------------------------
void SetBlob(TArray<uint8> value)
{
Data = 0;
Type = BLOB;
Blob = MakeShared<TArray<uint8>>(std::move(value));
}
const TArray<uint8> & AsBlobValue() const
{
check(IsBlob());
static const TArray<uint8> empty;
return Blob.IsValid() ? *Blob : empty;
}
bool IsBlob() const
{
return Type == BLOB;
}
//-------------------------------------------------------------------------
/// Cast the value to T.
template <class T>
T GetValue() const
{
static const bool isNumber = (std::is_integral<T>::value || std::is_floating_point<T>::value);
if(IsFloat())
{
if(isNumber)
{
const auto value = AsFloatValue();
return Cast<T, isNumber>::eval(value);
}
}
else if(IsInt())
{
if(isNumber)
{
const auto value = AsIntValue();
return Cast<T, isNumber>::eval(value);
}
}
else if(IsBool())
{
if(isNumber)
{
const auto value = AsBoolValue();
return Cast<T, isNumber>::eval(value);
}
}
else if(IsString())
{
const bool isString = std::is_same<T, FName>::value;
if(isString)
{
const auto value = AsStringValue();
return Cast<T, isString>::eval(value);
}
}
else if(IsBlob())
{
const bool isBlob = std::is_same<T, TArray<uint8>>::value;
if(isBlob)
{
return Cast<T, isBlob>::eval(AsBlobValue());
}
}
return T();
}
private:
template <class T, bool>
struct Cast
{
template <class U>
static T eval(const U &)
{
return T();
}
};
private:
int32 Type;
int64 Data;
TSharedPtr<TArray<uint8>> Blob;
};
template <class T>
struct FOscDataElemStruct::Cast<T, true>
{
static T eval(double value)
{
if(std::is_integral<T>::value)
{
value += 0.4999999;
}
return static_cast<T>(value);
}
template <class U>
static T eval(const U & value)
{
return static_cast<T>(value);
}
};
template <>
struct FOscDataElemStruct::Cast<bool, true>
{
template <class U>
static bool eval(const U & value)
{
return value != 0;
}
};
@@ -1,31 +0,0 @@
#pragma once
#include "OscDataElemStruct.h"
#include "OscDataStruct.generated.h"
USTRUCT()
struct FOscDataStruct
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
int32 Index;
UPROPERTY()
TArray<FOscDataElemStruct> Queue;
FOscDataStruct() : Index(0)
{ }
FOscDataElemStruct Pop()
{
const auto idx = std::max(Index, 0);
if(idx < Queue.Num())
{
++Index;
return Queue[idx];
}
return FOscDataElemStruct();
}
};
@@ -1,315 +0,0 @@
#include "OscPrivatePCH.h"
#include "OscSettings.h"
#include "OscFunctionLibrary.h"
#include "oscpack/osc/OscOutboundPacketStream.h"
template <class T>
static inline
void PopValueImpl(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, T & Value)
{
if(input.Num() > 0)
{
output.Reserve(input.Num() - 1);
for(int32 i=1, n=input.Num(); i!=n; ++i)
{
output.Add(input[i]);
}
Value = input[0].GetValue<T>();
}
else
{
output.Empty();
Value = FOscDataElemStruct().GetValue<T>();
}
}
void UOscFunctionLibrary::PopBool(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, bool & Value)
{
PopValueImpl(input, output, Value);
}
void UOscFunctionLibrary::PopFloat(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, float & Value)
{
PopValueImpl(input, output, Value);
}
void UOscFunctionLibrary::PopInt(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, int32 & Value)
{
PopValueImpl(input, output, Value);
}
void UOscFunctionLibrary::PopString(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, FName & Value)
{
PopValueImpl(input, output, Value);
}
void UOscFunctionLibrary::PopBlob(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, TArray<uint8> & Value)
{
PopValueImpl(input, output, Value);
}
void UOscFunctionLibrary::PushBool(const TArray<FOscDataElemStruct> & input, bool Value, TArray<FOscDataElemStruct> & output)
{
output = input;
FOscDataElemStruct elem;
elem.SetBool(Value);
output.Add(elem);
}
void UOscFunctionLibrary::PushFloat(const TArray<FOscDataElemStruct> & input, float Value, TArray<FOscDataElemStruct> & output)
{
output = input;
FOscDataElemStruct elem;
elem.SetFloat(Value);
output.Add(elem);
}
void UOscFunctionLibrary::PushInt(const TArray<FOscDataElemStruct> & input, int32 Value, TArray<FOscDataElemStruct> & output)
{
output = input;
FOscDataElemStruct elem;
elem.SetInt(Value);
output.Add(elem);
}
void UOscFunctionLibrary::PushString(const TArray<FOscDataElemStruct> & input, FName Value, TArray<FOscDataElemStruct> & output)
{
if(Value.GetDisplayNameEntry()->IsWide())
{
const auto tmp = Value.GetPlainNameString();
UE_LOG(LogOSC, Error, TEXT("Invalid string argument \"%s\": ASCII only"), *tmp);
return;
}
output = input;
FOscDataElemStruct elem;
elem.SetString(Value);
output.Add(elem);
}
void UOscFunctionLibrary::PushBlob(const TArray<FOscDataElemStruct> & input, const TArray<uint8> & Value, TArray<FOscDataElemStruct> & output)
{
output = input;
FOscDataElemStruct elem;
elem.SetBlob(Value);
output.Add(elem);
}
bool UOscFunctionLibrary::AsBool(const FOscDataElemStruct & input)
{
return input.GetValue<bool>();
}
float UOscFunctionLibrary::AsFloat(const FOscDataElemStruct & input)
{
return input.GetValue<float>();
}
int32 UOscFunctionLibrary::AsInt(const FOscDataElemStruct & input)
{
return input.GetValue<int32>();
}
FName UOscFunctionLibrary::AsString(const FOscDataElemStruct & input)
{
return input.GetValue<FName>();
}
TArray<uint8> UOscFunctionLibrary::AsBlob(const FOscDataElemStruct & input)
{
return input.GetValue<TArray<uint8>>();
}
FOscDataElemStruct UOscFunctionLibrary::FromBool(bool input)
{
FOscDataElemStruct result;
result.SetBool(input);
return result;
}
FOscDataElemStruct UOscFunctionLibrary::FromFloat(float input)
{
FOscDataElemStruct result;
result.SetFloat(input);
return result;
}
FOscDataElemStruct UOscFunctionLibrary::FromInt(int32 input)
{
FOscDataElemStruct result;
result.SetInt(input);
return result;
}
FOscDataElemStruct UOscFunctionLibrary::FromString(FName input)
{
FOscDataElemStruct result;
result.SetString(input);
return result;
}
FOscDataElemStruct UOscFunctionLibrary::FromBlob(const TArray<uint8> & input)
{
FOscDataElemStruct result;
result.SetBlob(input);
return result;
}
namespace
{
bool isValidAddress(const FName & Address)
{
if(!Address.IsValid())
{
UE_LOG(LogOSC, Error, TEXT("Empty OSC address"));
return false;
}
if(Address.GetDisplayNameEntry()->IsWide())
{
const auto tmp = Address.GetPlainNameString();
UE_LOG(LogOSC, Error, TEXT("Invalid OSC address \"%s\": ASCII only"), *tmp);
return false;
}
if(Address.GetPlainANSIString()[0] != '/')
{
const auto tmp = Address.GetPlainNameString();
UE_LOG(LogOSC, Error, TEXT("Invalid OSC address \"%s\": must start with '/'"), *tmp);
return false;
}
return true;
}
void appendMessage(osc::OutboundPacketStream & output, FName Address, const TArray<FOscDataElemStruct> & Data)
{
output << osc::BeginMessage(Address.GetPlainANSIString());
if(output.State() != osc::SUCCESS)
{
return;
}
for(const auto & elem : Data)
{
if(elem.IsFloat())
{
output << (float)elem.AsFloatValue();
}
else if(elem.IsInt())
{
output << (int32)elem.AsIntValue();
}
else if(elem.IsBool())
{
output << elem.AsBoolValue();
}
else if(elem.IsString())
{
output << elem.AsStringValue().GetPlainANSIString();
}
else if(elem.IsBlob())
{
const TArray<uint8> & value = elem.AsBlobValue();
output << osc::Blob(value.GetData(), value.Num());
}
if(output.State() != osc::SUCCESS)
{
return;
}
}
output << osc::EndMessage;
}
TArray<uint8> GlobalBuffer(TArray<uint8>(), 1024);
}
void UOscFunctionLibrary::SendOsc(FName Address, const TArray<FOscDataElemStruct> & Data, int32 TargetIndex)
{
if(!isValidAddress(Address))
{
return;
}
static_assert(sizeof(uint8) == sizeof(char), "Cannot cast uint8 to char");
osc::OutboundPacketStream output((char *)GlobalBuffer.GetData(), GlobalBuffer.Max());
check(reinterpret_cast<const void *>(GlobalBuffer.GetData()) == reinterpret_cast<const void *>(output.Data()));
appendMessage(output, Address, Data);
if(output.State() == osc::OUT_OF_BUFFER_MEMORY_ERROR)
{
GlobalBuffer.Reserve(GlobalBuffer.Max() * 2); // not enough memory: double the size
SendOsc(Address, Data, TargetIndex); // try again
return;
}
if(output.State() == osc::SUCCESS)
{
GetMutableDefault<UOscSettings>()->Send(GlobalBuffer.GetData(), output.Size(), TargetIndex);
}
else
{
UE_LOG(LogOSC, Error, TEXT("OSC Send Message Error: %s"), osc::errorString(output.State()));
}
}
void UOscFunctionLibrary::SendOscBundle(const TArray<FOscMessageStruct> & Messages, int32 TargetIndex)
{
static_assert(sizeof(uint8) == sizeof(char), "Cannot cast uint8 to char");
osc::OutboundPacketStream output((char *)GlobalBuffer.GetData(), GlobalBuffer.Max());
check(reinterpret_cast<const void *>(GlobalBuffer.GetData()) == reinterpret_cast<const void *>(output.Data()));
output << osc::BeginBundle();
for(const auto & message : Messages)
{
if(!isValidAddress(message.Address))
{
return;
}
appendMessage(output, message.Address, message.Data);
if(output.State() == osc::OUT_OF_BUFFER_MEMORY_ERROR)
{
GlobalBuffer.Reserve(GlobalBuffer.Max() * 2); // not enough memory: double the size
SendOscBundle(Messages, TargetIndex); // try again
return;
}
if(output.State() != osc::SUCCESS)
{
UE_LOG(LogOSC, Error, TEXT("OSC Send Bundle Error: %s"), osc::errorString(output.State()));
return;
}
}
output << osc::EndBundle;
if(output.State() == osc::OUT_OF_BUFFER_MEMORY_ERROR)
{
GlobalBuffer.Reserve(GlobalBuffer.Max() * 2); // not enough memory: double the size
SendOscBundle(Messages, TargetIndex); // try again
return;
}
if(output.State() == osc::SUCCESS)
{
GetMutableDefault<UOscSettings>()->Send(GlobalBuffer.GetData(), output.Size(), TargetIndex);
}
else
{
UE_LOG(LogOSC, Error, TEXT("OSC Send Bundle Error: %s"), osc::errorString(output.State()));
}
}
int32 UOscFunctionLibrary::AddSendOscTarget(FString IpPort)
{
return GetMutableDefault<UOscSettings>()->GetOrAddSendTarget(IpPort);
}
@@ -1,128 +0,0 @@
#pragma once
#include "OscDataElemStruct.h"
#include "OscMessageStruct.h"
#include "OscFunctionLibrary.generated.h"
UCLASS()
class UOscFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/// Get the next value from an OSC message as a boolean.
UFUNCTION(BlueprintPure, Category=OSC)
static void PopBool(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, bool & Value);
/// Get the next value from an OSC message as a floating point.
UFUNCTION(BlueprintPure, Category=OSC)
static void PopFloat(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, float & Value);
/// Get the next value from an OSC message as a integer.
UFUNCTION(BlueprintPure, Category=OSC)
static void PopInt(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, int32 & Value);
/// Get the next value from an OSC message as a string.
UFUNCTION(BlueprintPure, Category=OSC)
static void PopString(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, FName & Value);
/// Get the next value from an OSC message as a blob.
UFUNCTION(BlueprintPure, Category=OSC)
static void PopBlob(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, TArray<uint8> & Value);
/// Add a boolean value to an OSC message.
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
static void PushBool(const TArray<FOscDataElemStruct> & input, bool Value, TArray<FOscDataElemStruct> & output);
/// Add a floating point value to an OSC message.
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
static void PushFloat(const TArray<FOscDataElemStruct> & input, float Value, TArray<FOscDataElemStruct> & output);
/// Add a integer value to an OSC message.
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
static void PushInt(const TArray<FOscDataElemStruct> & input, int32 Value, TArray<FOscDataElemStruct> & output);
/// Add a string value to an OSC message.
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
static void PushString(const TArray<FOscDataElemStruct> & input, FName Value, TArray<FOscDataElemStruct> & output);
/// Add a blob to an OSC message.
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
static void PushBlob(const TArray<FOscDataElemStruct> & input, const TArray<uint8> & Value, TArray<FOscDataElemStruct> & output);
/// Interpret an OSC argument as a boolean
UFUNCTION(BlueprintPure, Category=OSC)
static bool AsBool(const FOscDataElemStruct & input);
/// Interpret an OSC argument as a floating point.
UFUNCTION(BlueprintPure, Category=OSC)
static float AsFloat(const FOscDataElemStruct & input);
/// Interpret an OSC argument as a integer.
UFUNCTION(BlueprintPure, Category=OSC)
static int32 AsInt(const FOscDataElemStruct & input);
/// Interpret an OSC argument as a string.
UFUNCTION(BlueprintPure, Category=OSC)
static FName AsString(const FOscDataElemStruct & input);
/// Interpret an OSC argument as a blob.
UFUNCTION(BlueprintPure, Category=OSC)
static TArray<uint8> AsBlob(const FOscDataElemStruct & input);
/// Create an OSC argument from a boolean
UFUNCTION(BlueprintPure, Category=OSC)
static FOscDataElemStruct FromBool(bool input);
/// Create an OSC argument from a floating point.
UFUNCTION(BlueprintPure, Category=OSC)
static FOscDataElemStruct FromFloat(float input);
/// Create an OSC argument from a integer.
UFUNCTION(BlueprintPure, Category=OSC)
static FOscDataElemStruct FromInt(int32 input);
/// Create an OSC argument from a string.
UFUNCTION(BlueprintPure, Category=OSC)
static FOscDataElemStruct FromString(FName input);
/// Create an OSC argument from a blob.
UFUNCTION(BlueprintPure, Category=OSC)
static FOscDataElemStruct FromBlob(const TArray<uint8> & input);
/**
* @brief Send an OSC message.
* @param Address OSC address.
* @param Data result of successive PushFloat/Int/String/etc.
* @param TargetIndex index of the destination, -1 for all destinations. (SendTarget list of the plugin settings)
*/
UFUNCTION(BlueprintCallable, Category=OSC, meta=(AutoCreateRefTerm = "Data"))
static void SendOsc(FName Address, const TArray<FOscDataElemStruct> & Data, int32 TargetIndex);
/**
* @brief Send several OSC messages in an OSC bundle.
* @param Messages of the bundle.
* @param TargetIndex index of the destination, -1 for all destinations. (SendTarget list of the plugin settings)
*/
UFUNCTION(BlueprintCallable, Category=OSC)
static void SendOscBundle(const TArray<FOscMessageStruct> & Messages, int32 TargetIndex);
/**
* @brief Add Ip:Port to the available OSC send targets.
* @param IpPort "ip:port". e.g. "192.168.0.1:7777"
* @return The created TargetIndex to pass to the SendOsc function.
*
* Use this function to add target at runtime. Generally, it is best
* to define your targets in the OSC plugin settings.
*
* @see SendOsc
*/
UFUNCTION(BlueprintCallable, Category=OSC)
static int32 AddSendOscTarget(FString IpPort);
};
@@ -1,17 +0,0 @@
#pragma once
#include "OscDataElemStruct.h"
#include "OscMessageStruct.generated.h"
USTRUCT(BlueprintType)
struct FOscMessageStruct
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FName Address;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<FOscDataElemStruct> Data;
};
@@ -1,62 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCEXCEPTION_H
#define INCLUDED_OSCPACK_OSCEXCEPTION_H
#include <exception>
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 */
@@ -1,127 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H
#define INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H
/*
Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined
We try to use preprocessor symbols to deduce the host endianness.
Alternatively you can define one of the above symbols from the command line.
Usually you do this with the -D flag to the compiler. e.g.:
$ g++ -DOSC_HOST_LITTLE_ENDIAN ...
*/
#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN)
// endianness defined on the command line. nothing to do here.
#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE)
// assume that __WIN32__ is only defined on little endian systems
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif defined(__APPLE__)
#if defined(__LITTLE_ENDIAN__)
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif defined(__BIG_ENDIAN__)
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
// should cover gcc and clang
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#else
// gcc defines __LITTLE_ENDIAN__ and __BIG_ENDIAN__
// for others used here see http://sourceforge.net/p/predef/wiki/Endianness/
#if (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \
|| (defined(__ARMEL__) && !defined(__ARMEB__)) \
|| (defined(__AARCH64EL__) && !defined(__AARCH64EB__)) \
|| (defined(_MIPSEL) && !defined(_MIPSEB)) \
|| (defined(__MIPSEL) && !defined(__MIPSEB)) \
|| (defined(__MIPSEL__) && !defined(__MIPSEB__))
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \
|| (defined(__ARMEB__) && !defined(__ARMEL__)) \
|| (defined(__AARCH64EB__) && !defined(__AARCH64EL__)) \
|| (defined(_MIPSEB) && !defined(_MIPSEL)) \
|| (defined(__MIPSEB) && !defined(__MIPSEL)) \
|| (defined(__MIPSEB__) && !defined(__MIPSEL__))
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#endif
#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN)
#error please edit OSCHostEndianness.h or define one of {OSC_HOST_LITTLE_ENDIAN, OSC_HOST_BIG_ENDIAN} to configure endianness
#endif
#endif /* INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H */
@@ -1,728 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscPrivatePCH.h"
#include "OscOutboundPacketStream.h"
#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32)
#include <malloc.h> // for alloca
#else
//#include <alloca.h> // alloca on Linux (also OSX)
#include <stdlib.h> // alloca on OSX and FreeBSD (and Linux?)
#endif
#include <cassert>
#include <cstring> // memcpy, memmove, strcpy, strlen
#include <cstddef> // 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<int32*>(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<uint32*>(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<int64*>(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<uint64*>(p) = x;
#endif
}
OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity )
: data_( buffer )
, end_( data_ + capacity )
, typeTagsCurrent_( end_ )
, messageCursor_( data_ )
, argumentCurrent_( data_ )
, elementSizePtr_( 0 )
, messageIsInProgress_( false )
, state_( SUCCESS )
{
// 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<uint32*>(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<uint32*>(beginPtr) =
(uint32)(reinterpret_cast<char*>(elementSizePtr_) - data_);
elementSizePtr_ = reinterpret_cast<uint32*>(beginPtr);
return beginPtr + 4;
}
}
void OutboundPacketStream::EndElement( char *endPtr )
{
assert( elementSizePtr_ != 0 );
if( elementSizePtr_ == reinterpret_cast<uint32*>(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<uint32*>(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<char*>(elementSizePtr_);
// assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb
uint32 elementSize = static_cast<uint32>(d - 4);
FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
// finally, we reset the element size ptr to the containing element
elementSizePtr_ = previousElementSizePtr;
}
}
bool OutboundPacketStream::ElementSizeSlotRequired() const
{
return (elementSizePtr_ != 0);
}
Errors OutboundPacketStream::CheckForAvailableBundleSpace()
{
std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
return (required > Capacity()) ? OUT_OF_BUFFER_MEMORY_ERROR : SUCCESS;
}
Errors 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;
return (required > Capacity()) ? OUT_OF_BUFFER_MEMORY_ERROR : SUCCESS;
}
Errors 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 );
return (required > Capacity()) ? OUT_OF_BUFFER_MEMORY_ERROR : SUCCESS;
}
void OutboundPacketStream::Clear()
{
typeTagsCurrent_ = end_;
messageCursor_ = data_;
argumentCurrent_ = data_;
elementSizePtr_ = 0;
messageIsInProgress_ = false;
state_ = SUCCESS;
}
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 )
{
check( !IsMessageInProgress() )
check( state_ == SUCCESS )
state_ = CheckForAvailableBundleSpace();
if(state_ == SUCCESS)
{
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;
check( IsBundleInProgress() )
check( !IsMessageInProgress() )
check( state_ == SUCCESS )
EndElement( messageCursor_ );
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs )
{
check( !IsMessageInProgress() )
check( state_ == SUCCESS )
state_ = CheckForAvailableMessageSpace( rhs.addressPattern );
if(state_ == SUCCESS)
{
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;
check( IsMessageInProgress() )
check( state_ == SUCCESS )
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 )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(0);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG);
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs )
{
(void) rhs;
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(0);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = NIL_TYPE_TAG;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs )
{
(void) rhs;
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(0);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = INFINITUM_TYPE_TAG;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(4);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = INT32_TYPE_TAG;
FromInt32( argumentCurrent_, rhs );
argumentCurrent_ += 4;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(4);
if(state_ == SUCCESS)
{
*(--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<float*>(argumentCurrent_) = rhs;
#endif
argumentCurrent_ += 4;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( char rhs )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(4);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = CHAR_TYPE_TAG;
FromInt32( argumentCurrent_, rhs );
argumentCurrent_ += 4;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(4);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG;
FromUInt32( argumentCurrent_, rhs );
argumentCurrent_ += 4;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(4);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG;
FromUInt32( argumentCurrent_, rhs );
argumentCurrent_ += 4;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(8);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = INT64_TYPE_TAG;
FromInt64( argumentCurrent_, rhs );
argumentCurrent_ += 8;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(8);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG;
FromUInt64( argumentCurrent_, rhs );
argumentCurrent_ += 8;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(8);
if(state_ == SUCCESS)
{
*(--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<double*>(argumentCurrent_) = rhs;
#endif
argumentCurrent_ += 8;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
if(state_ == SUCCESS)
{
*(--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 )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
if(state_ == SUCCESS)
{
*(--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 )
{
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) );
if(state_ == SUCCESS)
{
*(--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;
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(0);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs )
{
(void) rhs;
check( state_ == SUCCESS )
state_ = CheckForAvailableArgumentSpace(0);
if(state_ == SUCCESS)
{
*(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG;
}
return *this;
}
} // namespace osc
@@ -1,130 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H
#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H
#include <cstring> // size_t
#include "OscTypes.h"
namespace osc{
class OutboundPacketStream{
public:
OutboundPacketStream( char *buffer, std::size_t capacity );
~OutboundPacketStream();
Errors State() const { return state_; }
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;
Errors CheckForAvailableBundleSpace();
Errors CheckForAvailableMessageSpace( const char *addressPattern );
Errors 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_;
Errors state_;
};
} // namespace osc
#endif /* INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H */
@@ -1,896 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscPrivatePCH.h"
#include "OscReceivedElements.h"
#include "OscHostEndianness.h"
#include <cstddef> // ptrdiff_t
namespace osc{
// return the first 4 byte boundary after the end of a str4
// be careful about calling this version if you don't know whether
// the string is terminated correctly.
static inline const char* FindStr4End( const char *p )
{
if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
return p + 4;
p += 3;
while( *p )
p += 4;
return p + 1;
}
// return the first 4 byte boundary after the end of a str4
// returns 0 if p == end or if the string is unterminated
static inline const char* FindStr4End( const char *p, const char *end )
{
if( p >= end )
return 0;
if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
return p + 4;
p += 3;
end -= 1;
while( p < end && *p )
p += 4;
if( *p )
return 0;
else
return p + 1;
}
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(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == TRUE_TYPE_TAG )
return true;
else if( *typeTagPtr_ == FALSE_TYPE_TAG )
return false;
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return false;
}
bool ReceivedMessageArgument::AsBoolUnchecked(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == TRUE_TYPE_TAG )
return true;
else
return false;
return false;
}
int32 ReceivedMessageArgument::AsInt32(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == INT32_TYPE_TAG )
return AsInt32Unchecked();
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return 0;
}
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(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == FLOAT_TYPE_TAG )
return AsFloatUnchecked();
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return 0.f;
}
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(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == CHAR_TYPE_TAG )
return AsCharUnchecked();
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return '\0';
}
char ReceivedMessageArgument::AsCharUnchecked() const
{
return (char)ToInt32( argumentPtr_ );
}
uint32 ReceivedMessageArgument::AsRgbaColor(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == RGBA_COLOR_TYPE_TAG )
return AsRgbaColorUnchecked();
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return 0u;
}
uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
{
return ToUInt32( argumentPtr_ );
}
uint32 ReceivedMessageArgument::AsMidiMessage(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG )
return AsMidiMessageUnchecked();
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return 0u;
}
uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
{
return ToUInt32( argumentPtr_ );
}
int64 ReceivedMessageArgument::AsInt64(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == INT64_TYPE_TAG )
return AsInt64Unchecked();
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return 0LL;
}
int64 ReceivedMessageArgument::AsInt64Unchecked() const
{
return ToInt64( argumentPtr_ );
}
uint64 ReceivedMessageArgument::AsTimeTag(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == TIME_TAG_TYPE_TAG )
return AsTimeTagUnchecked();
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return 0ULL;
}
uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
{
return ToUInt64( argumentPtr_ );
}
double ReceivedMessageArgument::AsDouble(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == DOUBLE_TYPE_TAG )
return AsDoubleUnchecked();
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return 0.;
}
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(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == STRING_TYPE_TAG )
return argumentPtr_;
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return "";
}
const char* ReceivedMessageArgument::AsSymbol(Errors & state) const
{
state = SUCCESS;
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == SYMBOL_TYPE_TAG )
return argumentPtr_;
else
state = WRONG_ARGUMENT_TYPE_ERROR;
return "";
}
void ReceivedMessageArgument::AsBlob( const void*& data, osc_bundle_element_size_t& size, Errors & state ) const
{
if( !typeTagPtr_ )
state = MISSING_ARGUMENT_ERROR;
else if( *typeTagPtr_ == BLOB_TYPE_TAG )
AsBlobUnchecked( data, size, state );
else
state = WRONG_ARGUMENT_TYPE_ERROR;
}
void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size, Errors & state ) 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) )
{
state = MALFORMED_MESSAGE_INVALID_BLOB_SIZE_ERROR;
}
else
{
state = SUCCESS;
size = sizeResult;
data = (void*)(argumentPtr_+ osc::OSC_SIZEOF_INT32);
}
}
std::size_t ReceivedMessageArgument::ComputeArrayItemCount(Errors & state) const
{
// it is only valid to call ComputeArrayItemCount when the argument is the array start marker
if( !IsArrayBegin() )
{
state = WRONG_ARGUMENT_TYPE_ERROR;
return 0;
}
state = SUCCESS;
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() )
, state_( SUCCESS )
{
Init( packet.Contents(), packet.Size() );
}
ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
: addressPattern_( bundleElement.Contents() )
, state_( SUCCESS )
{
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) )
{
state_ = MALFORMED_MESSAGE_INVALID_SIZE_ERROR;
return;
}
if( size == 0 )
{
state_ = MALFORMED_MESSAGE_ZERO_SIZE_ERROR;
return;
}
if( !IsMultipleOf4(size) )
{
state_ = MALFORMED_MESSAGE_NOT_MULTIPLE_OF_4_ERROR;
return;
}
const char *end = message + size;
typeTagsBegin_ = FindStr4End( addressPattern_, end );
if( typeTagsBegin_ == 0 ){
// address pattern was not terminated before end
state_ = MALFORMED_MESSAGE_UNTERMINATED_ADDRESS_PATTERN_ERROR;
return;
}
if( typeTagsBegin_ == end ){
// message consists of only the address pattern - no arguments or type tags.
typeTagsBegin_ = 0;
typeTagsEnd_ = 0;
arguments_ = 0;
}else{
if( *typeTagsBegin_ != ',' )
{
state_ = MALFORMED_MESSAGE_NO_TYPE_TAGS_ERROR;
return;
}
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 )
{
state_ = MALFORMED_MESSAGE_UNTERMINATED_TYPE_TAGS_ERROR;
return;
}
++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 )
{
state_ = MALFORMED_MESSAGE_ARGUMENT_EXCEED_MSG_SIZE_ERROR;
return;
}
argument += 4;
if( argument > end )
{
state_ = MALFORMED_MESSAGE_ARGUMENT_EXCEED_MSG_SIZE_ERROR;
return;
}
break;
case INT64_TYPE_TAG:
case TIME_TAG_TYPE_TAG:
case DOUBLE_TYPE_TAG:
if( argument == end )
{
state_ = MALFORMED_MESSAGE_ARGUMENT_EXCEED_MSG_SIZE_ERROR;
return;
}
argument += 8;
if( argument > end )
{
state_ = MALFORMED_MESSAGE_ARGUMENT_EXCEED_MSG_SIZE_ERROR;
return;
}
break;
case STRING_TYPE_TAG:
case SYMBOL_TYPE_TAG:
if( argument == end )
{
state_ = MALFORMED_MESSAGE_ARGUMENT_EXCEED_MSG_SIZE_ERROR;
return;
}
argument = FindStr4End( argument, end );
if( argument == 0 )
{
state_ = MALFORMED_MESSAGE_UNTERMINATED_STRING_ERROR;
return;
}
break;
case BLOB_TYPE_TAG:
{
if( argument + osc::OSC_SIZEOF_INT32 > end )
{
state_ = MALFORMED_MESSAGE_ARGUMENT_EXCEED_MSG_SIZE_ERROR;
return;
}
// 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 )
{
state_ = MALFORMED_MESSAGE_ARGUMENT_EXCEED_MSG_SIZE_ERROR;
return;
}
}
break;
default:
state_ = MALFORMED_MESSAGE_UNKNOWN_TYPE_TAG_ERROR;
return;
}
}while( *++typeTag != '\0' );
typeTagsEnd_ = typeTag;
if( arrayLevel != 0 )
{
state_ = MALFORMED_MESSAGE_UNTERMINATED_ARRAY_ERROR;
return;
}
}
// 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 )
, state_( SUCCESS )
{
Init( packet.Contents(), packet.Size() );
}
ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
: elementCount_( 0 )
, state_( SUCCESS )
{
Init( bundleElement.Contents(), bundleElement.Size() );
}
void ReceivedBundle::Init( const char *bundle, osc_bundle_element_size_t size )
{
if( !IsValidElementSizeValue(size) )
{
state_ = MALFORMED_BUNDLE_INVALID_SIZE_ERROR;
return;
}
if( size < 16 )
{
state_ = MALFORMED_BUNDLE_TOO_SHORT_ERROR;
return;
}
if( !IsMultipleOf4(size) )
{
state_ = MALFORMED_BUNDLE_NOT_MULTIPLE_OF_4_ERROR;
return;
}
if( bundle[0] != '#'
|| bundle[1] != 'b'
|| bundle[2] != 'u'
|| bundle[3] != 'n'
|| bundle[4] != 'd'
|| bundle[5] != 'l'
|| bundle[6] != 'e'
|| bundle[7] != '\0' )
{
state_ = MALFORMED_BUNDLE_INVALID_ADDRESS_PATTERN_ERROR;
return;
}
end_ = bundle + size;
timeTag_ = bundle + 8;
const char *p = timeTag_ + 8;
while( p < end_ ){
if( p + osc::OSC_SIZEOF_INT32 > end_ )
{
state_ = MALFORMED_BUNDLE_TOO_SHORT_FOR_ELEMENT_SIZE_ERROR;
return;
}
// treat element size as an unsigned int for the purposes of this calculation
uint32 elementSize = ToUInt32( p );
if( (elementSize & ((uint32)0x03)) != 0 )
{
state_ = MALFORMED_BUNDLE_ELEMENT_NOT_MULTIPLE_OF_4_ERROR;
return;
}
p += osc::OSC_SIZEOF_INT32 + elementSize;
if( p > end_ )
{
state_ = MALFORMED_BUNDLE_TOO_SHORT_FOR_ELEMENT_ERROR;
return;
}
++elementCount_;
}
if( p != end_ )
{
state_ = MALFORMED_BUNDLE_CONTENT_ERROR;
}
}
uint64 ReceivedBundle::TimeTag() const
{
return ToUInt64( timeTag_ );
}
} // namespace osc
@@ -1,581 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H
#define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H
#include <cassert>
#include <cstddef>
#include <cstring> // size_t
#include "OscTypes.h"
namespace osc{
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, &state_) ) {}
ReceivedPacket( const char *contents, std::size_t size )
: contents_( contents )
, size_( ValidateSize( (osc_bundle_element_size_t)size, &state_ ) ) {}
#if !(defined(__x86_64__) || defined(_M_X64))
ReceivedPacket( const char *contents, int size )
: contents_( contents )
, size_( ValidateSize( (osc_bundle_element_size_t)size, &state_ ) ) {}
#endif
bool IsMessage() const { return !IsBundle(); }
bool IsBundle() const;
osc_bundle_element_size_t Size() const { return size_; }
const char *Contents() const { return contents_; }
Errors State() const { return state_; }
private:
const char *contents_;
osc_bundle_element_size_t size_;
Errors state_;
static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size, Errors * state )
{
// 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) )
{
*state = MALFORMED_PACKET_INVALID_SIZE_ERROR;
return 0;
}
if( size == 0 )
{
*state = MALFORMED_PACKET_ZERO_SIZE_ERROR;
return 0;
}
if( !IsMultipleOf4(size) )
{
*state = MALFORMED_PACKET_NOT_MULTIPLE_OF_4_ERROR;
return 0;
}
*state = SUCCESS;
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(Errors & state) const;
bool AsBoolUnchecked(Errors & state) 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(Errors & state) const;
int32 AsInt32Unchecked() const;
bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; }
float AsFloat(Errors & state) const;
float AsFloatUnchecked() const;
bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; }
char AsChar(Errors & state) const;
char AsCharUnchecked() const;
bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; }
uint32 AsRgbaColor(Errors & state) const;
uint32 AsRgbaColorUnchecked() const;
bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; }
uint32 AsMidiMessage(Errors & state) const;
uint32 AsMidiMessageUnchecked() const;
bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; }
int64 AsInt64(Errors & state) const;
int64 AsInt64Unchecked() const;
bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; }
uint64 AsTimeTag(Errors & state) const;
uint64 AsTimeTagUnchecked() const;
bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; }
double AsDouble(Errors & state) const;
double AsDoubleUnchecked() const;
bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; }
const char* AsString(Errors & state) const;
const char* AsStringUnchecked() const { return argumentPtr_; }
bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; }
const char* AsSymbol(Errors & state) 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, Errors & state ) const;
void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size, Errors & state ) 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(Errors & state) 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 )
, state_( SUCCESS ) {}
ReceivedMessageArgumentIterator p_, end_;
Errors state_;
public:
Errors State() const { return state_; }
// end of stream
bool Eos() const { return p_ == end_; }
ReceivedMessageArgumentStream& operator>>( bool& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs = (*p_++).AsBool(state_);
}
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() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs = (*p_++).AsInt32(state_);
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( float& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs = (*p_++).AsFloat(state_);
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( char& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs = (*p_++).AsChar(state_);
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs.value = (*p_++).AsRgbaColor(state_);
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs.value = (*p_++).AsMidiMessage(state_);
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( int64& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs = (*p_++).AsInt64(state_);
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( TimeTag& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs.value = (*p_++).AsTimeTag(state_);
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( double& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs = (*p_++).AsDouble(state_);
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( Blob& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
(*p_++).AsBlob( rhs.data, rhs.size, state_ );
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( const char*& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs = (*p_++).AsString(state_);
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( Symbol& rhs )
{
if( Eos() )
{
state_ = MISSING_ARGUMENT_ERROR;
}
else
{
rhs.value = (*p_++).AsSymbol(state_);
}
return *this;
}
ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs )
{
(void) rhs; // suppress unused parameter warning
if( Eos() )
{
state_ = EXCESS_ARGUMENT_ERROR;
}
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 );
Errors State() const { return state_; }
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<uint32>(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_;
Errors state_;
};
class ReceivedBundle{
void Init( const char *message, osc_bundle_element_size_t size );
public:
explicit ReceivedBundle( const ReceivedPacket& packet );
explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );
Errors State() const { return state_; }
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_;
Errors state_;
};
} // namespace osc
#endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */
@@ -1,103 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscPrivatePCH.h"
#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;
const TCHAR * errorString(Errors value)
{
static const TCHAR * ERROR_STR[] = {
TEXT("No Error"),
TEXT("Malformed packet"),
TEXT("Malformed packet: invalid size"),
TEXT("Malformed packet: zero size"),
TEXT("Malformed packet: not multiple of 4"),
TEXT("Malformed message"),
TEXT("Malformed message: invalid size"),
TEXT("Malformed message: zero size"),
TEXT("Malformed message: not multiple of 4"),
TEXT("Malformed message: invalid blob size"),
TEXT("Malformed message: unterminated address pattern"),
TEXT("Malformed message: unterminated string"),
TEXT("Malformed message: unterminated array"),
TEXT("Malformed message: no type tags"),
TEXT("Malformed message: unterminated type tags"),
TEXT("Malformed message: argument exceed msg size"),
TEXT("Malformed message: unknown type tag"),
TEXT("Malformed bundle"),
TEXT("Malformed bundle: invalid size"),
TEXT("Malformed bundle: invalid address pattern"),
TEXT("Malformed bundle: too short"),
TEXT("Malformed bundle: too short for element size"),
TEXT("Malformed bundle: too short for element"),
TEXT("Malformed bundle: not multiple of 4"),
TEXT("Malformed bundle: element not multiple of 4"),
TEXT("Malformed bundle: content"),
TEXT("Wrong argument type"),
TEXT("Missing argument"),
TEXT("Excess argument"),
TEXT("Out of buffer memory"),
};
static_assert((sizeof(ERROR_STR) / sizeof(*ERROR_STR) == ERRORS_COUNT), "Error messages mismatch");
if(value < 0 || value >= ERRORS_COUNT)
{
check(false);
return TEXT("Unknown error code");
}
return ERROR_STR[value];
}
} // namespace osc
@@ -1,289 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_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;
}
// 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);
}
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;
enum Errors {
SUCCESS = 0,
MALFORMED_PACKET_ERROR,
MALFORMED_PACKET_INVALID_SIZE_ERROR,
MALFORMED_PACKET_ZERO_SIZE_ERROR,
MALFORMED_PACKET_NOT_MULTIPLE_OF_4_ERROR,
MALFORMED_MESSAGE_ERROR,
MALFORMED_MESSAGE_INVALID_SIZE_ERROR,
MALFORMED_MESSAGE_ZERO_SIZE_ERROR,
MALFORMED_MESSAGE_NOT_MULTIPLE_OF_4_ERROR,
MALFORMED_MESSAGE_INVALID_BLOB_SIZE_ERROR,
MALFORMED_MESSAGE_UNTERMINATED_ADDRESS_PATTERN_ERROR,
MALFORMED_MESSAGE_UNTERMINATED_STRING_ERROR,
MALFORMED_MESSAGE_UNTERMINATED_ARRAY_ERROR,
MALFORMED_MESSAGE_NO_TYPE_TAGS_ERROR,
MALFORMED_MESSAGE_UNTERMINATED_TYPE_TAGS_ERROR,
MALFORMED_MESSAGE_ARGUMENT_EXCEED_MSG_SIZE_ERROR,
MALFORMED_MESSAGE_UNKNOWN_TYPE_TAG_ERROR,
MALFORMED_BUNDLE_ERROR,
MALFORMED_BUNDLE_INVALID_SIZE_ERROR,
MALFORMED_BUNDLE_INVALID_ADDRESS_PATTERN_ERROR,
MALFORMED_BUNDLE_TOO_SHORT_ERROR,
MALFORMED_BUNDLE_TOO_SHORT_FOR_ELEMENT_SIZE_ERROR,
MALFORMED_BUNDLE_TOO_SHORT_FOR_ELEMENT_ERROR,
MALFORMED_BUNDLE_NOT_MULTIPLE_OF_4_ERROR,
MALFORMED_BUNDLE_ELEMENT_NOT_MULTIPLE_OF_4_ERROR,
MALFORMED_BUNDLE_CONTENT_ERROR,
WRONG_ARGUMENT_TYPE_ERROR,
MISSING_ARGUMENT_ERROR,
EXCESS_ARGUMENT_ERROR,
OUT_OF_BUFFER_MEMORY_ERROR,
ERRORS_COUNT,
};
const TCHAR * errorString(Errors value);
} // namespace osc
#endif /* INCLUDED_OSCPACK_OSCTYPES_H */
@@ -1,19 +0,0 @@
#pragma once
// Target engine version. Used to enable compatibility code.
#define OSC_ENGINE_VERSION 40800
#ifndef OSC_EDITOR_BUILD
#error OSC_EDITOR_BUILD must be set by the OSC.Build.cs
#endif
/* Public Dependencies
*****************************************************************************/
#include "Networking.h"
/* Public Includes
*****************************************************************************/
@@ -1,146 +0,0 @@
#include "OscPrivatePCH.h"
#include "OscSettings.h"
#include "OscDispatcher.h"
#if OSC_EDITOR_BUILD
#include "Editor.h"
#endif
#define LOCTEXT_NAMESPACE "FOscModule"
class FOscModule : public IModuleInterface
{
public:
virtual void StartupModule( ) override
{
if(!FModuleManager::Get().LoadModule(TEXT("Networking")))
{
UE_LOG(LogOSC, Error, TEXT("Required module Networking failed to load"));
return;
}
#if OSC_EDITOR_BUILD
_mustListen = !GIsEditor; // must not listen now if IsEditor (listen when PIE), else (Standalone Game) listen now
FEditorDelegates::BeginPIE.AddRaw(this, &FOscModule::OnBeginPIE);
FEditorDelegates::EndPIE.AddRaw(this, &FOscModule::OnEndPIE);
#endif
_dispatcher = UOscDispatcher::Get();
HandleSettingsSaved();
// register settings
auto settingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
if(settingsModule)
{
auto settingsSection = settingsModule->RegisterSettings("Project", "Plugins", "OSC",
LOCTEXT("OscSettingsName", "OSC"),
LOCTEXT("OscSettingsDescription", "Configure the OSC plug-in."),
GetMutableDefault<UOscSettings>()
);
if (settingsSection.IsValid())
{
settingsSection->OnModified().BindRaw(this, &FOscModule::HandleSettingsSaved);
}
}
else
{
#if OSC_EDITOR_BUILD
UE_LOG(LogOSC, Warning, TEXT("Settings changed registration failed"));
#endif
}
UE_LOG(LogOSC, Display, TEXT("Startup succeed"));
}
virtual void ShutdownModule( ) override
{
UE_LOG(LogOSC, Display, TEXT("Shutdown"));
if(_dispatcher.IsValid())
{
auto settings = GetMutableDefault<UOscSettings>();
settings->ClearKeyInputs(*_dispatcher);
_dispatcher->Stop();
}
}
bool HandleSettingsSaved()
{
if(!_dispatcher.IsValid())
{
UE_LOG(LogOSC, Warning, TEXT("Cannot update settings"));
return false;
}
UE_LOG(LogOSC, Display, TEXT("Update settings"));
auto settings = GetMutableDefault<UOscSettings>();
// receive settings
#if OSC_EDITOR_BUILD
if(_mustListen)
{
Listen(settings);
}
#else
Listen(settings);
#endif
// send settings
settings->InitSendTargets();
// input settings
settings->UpdateKeyInputs(*_dispatcher);
return true;
}
void Listen(UOscSettings * settings)
{
FIPv4Address receiveAddress(0);
uint32_t receivePort;
if(UOscSettings::Parse(settings->ReceiveFrom, &receiveAddress, &receivePort))
{
_dispatcher->Listen(receiveAddress, receivePort, settings->MulticastLoopback);
}
else
{
UE_LOG(LogOSC, Error, TEXT("Fail to parse receive address: %s"), *settings->ReceiveFrom);
}
}
private:
#if OSC_EDITOR_BUILD
void OnBeginPIE(bool isSimulating)
{
_mustListen = true;
check(_dispatcher.IsValid())
auto settings = GetMutableDefault<UOscSettings>();
Listen(settings);
}
void OnEndPIE(bool isSimulating)
{
_mustListen = false;
_dispatcher->Stop();
}
bool _mustListen;
#endif
private:
TWeakObjectPtr<UOscDispatcher> _dispatcher;
};
IMPLEMENT_MODULE(FOscModule, OSC);
DEFINE_LOG_CATEGORY(LogOSC);
#undef LOCTEXT_NAMESPACE
@@ -1,22 +0,0 @@
#pragma once
#include "Osc.h"
#include "Engine.h"
#include "ISettingsModule.h"
#include "ISettingsSection.h"
#include "ModuleManager.h"
#include "Sockets.h"
#include "SocketSubsystem.h"
#include "TaskGraphInterfaces.h"
#include "Runtime/Engine/Classes/Kismet/BlueprintFunctionLibrary.h"
#include "Runtime/Networking/Public/Networking.h"
#include "Runtime/Core/Public/Misc/Base64.h"
#include <algorithm>
#include <memory>
#include <tuple>
DECLARE_LOG_CATEGORY_EXTERN(LogOSC, Log, All);
@@ -1,178 +0,0 @@
#include "OscPrivatePCH.h"
#include "OscSettings.h"
#include "OscDispatcher.h"
UOscSettings::UOscSettings()
: ReceiveFrom("8000"),
MulticastLoopback(true),
_sendSocket(FUdpSocketBuilder(TEXT("OscSender")).Build())
{
SendTargets.Add(TEXT("127.0.0.1:8000"));
}
UOscSettings::UOscSettings(FVTableHelper & helper)
: _sendSocket(FUdpSocketBuilder(TEXT("OscSender")).Build())
{
// Does not need to be a valid object.
}
void UOscSettings::InitSendTargets()
{
UE_LOG(LogOSC, Display, TEXT("Send targets cleared"));
FString addressStr, portStr;
_sendAddresses.Empty();
_sendAddresses.Reserve(SendTargets.Num());
_sendAddressesIndex.Empty();
_sendAddressesIndex.Reserve(SendTargets.Num());
for(int32 i=0, n=SendTargets.Num(); i!=n; ++i)
{
const auto result = AddSendTarget(SendTargets[i]);
check(result == i);
}
}
int32 UOscSettings::GetOrAddSendTarget(const FString & ip_port)
{
const int32 * result = _sendAddressesIndex.Find(ip_port);
if(result)
{
return *result;
}
return AddSendTarget(ip_port);
}
int32 UOscSettings::AddSendTarget(const FString & ip_port)
{
auto target = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
FIPv4Address address(0);
uint32_t port;
if(Parse(ip_port, &address, &port) && address != FIPv4Address::Any)
{
target->SetIp(address.Value);
target->SetPort(port);
UE_LOG(LogOSC, Display, TEXT("Send target added: %s"), *ip_port);
}
else
{
UE_LOG(LogOSC, Error, TEXT("Fail to parse or invalid send target: %s"), *ip_port);
}
const auto result = _sendAddresses.Num();
_sendAddressesIndex.Emplace(ip_port, result);
_sendAddresses.Emplace(target);
return result;
}
static void SendImpl(FSocket *socket, const uint8 *buffer, int32 length, const FInternetAddr & target)
{
int32 bytesSent = 0;
while(length > 0)
{
socket->SendTo(buffer, length, bytesSent, target);
length -= bytesSent;
buffer += bytesSent;
}
}
void UOscSettings::Send(const uint8 *buffer, int32 length, int32 targetIndex)
{
if(targetIndex == -1)
{
for(const auto & address : _sendAddresses)
{
SendImpl(&_sendSocket.Get(), buffer, length, *address);
}
#if !NO_LOGGING
// Log sent packet
if(!LogOSC.IsSuppressed(ELogVerbosity::Verbose))
{
TArray<uint8> tmp;
tmp.Append(buffer, length);
const auto encoded = FBase64::Encode(tmp);
UE_LOG(LogOSC, Verbose, TEXT("SentAll: %s"), *encoded);
}
#endif
}
else if(targetIndex < _sendAddresses.Num())
{
SendImpl(&_sendSocket.Get(), buffer, length, *_sendAddresses[targetIndex]);
#if !NO_LOGGING
// Log sent packet
if(!LogOSC.IsSuppressed(ELogVerbosity::Verbose))
{
TArray<uint8> tmp;
tmp.Append(buffer, length);
const auto encoded = FBase64::Encode(tmp);
const auto target = _sendAddresses[targetIndex]->ToString(true);
UE_LOG(LogOSC, Verbose, TEXT("SentTo %s: %s"), *target, *encoded);
}
#endif
}
else
{
UE_LOG(LogOSC, Error, TEXT("Cannot send OSC: invalid targetIndex %d"), targetIndex);
}
}
bool UOscSettings::Parse(const FString & ip_port, FIPv4Address * address, uint32_t * port)
{
if(ip_port.IsEmpty())
{
return false;
}
FIPv4Address addressResult(0);
uint32_t portResult;
int32 sep = -1;
if(ip_port.FindChar(TEXT(':'), sep))
{
const auto ip = ip_port.Left(sep).Trim();
if(!FIPv4Address::Parse(ip, addressResult))
{
return false;
}
}
portResult = FCString::Atoi(&ip_port.GetCharArray()[sep+1]);
if(portResult == 0)
{
return false;
}
*address = addressResult;
*port = portResult;
return true;
}
void UOscSettings::ClearKeyInputs(UOscDispatcher & dispatcher)
{
for(auto & receiver : _keyReceivers)
{
// Unregister here, not in the OscReceiverInputKey destructor
// because it would crash at the application exit.
dispatcher.UnregisterReceiver(receiver.get());
}
_keyReceivers.Reset(0);
}
void UOscSettings::UpdateKeyInputs(UOscDispatcher & dispatcher)
{
ClearKeyInputs(dispatcher);
for(const auto & address : Inputs)
{
auto receiver = std::make_unique<OscReceiverInputKey>(address);
dispatcher.RegisterReceiver(receiver.get());
_keyReceivers.Add(std::move(receiver));
}
}
@@ -1,77 +0,0 @@
#pragma once
#include <utility>
#include "OscReceiverInputKey.h"
#include "OscSettings.generated.h"
class UOscDispatcher;
UCLASS(Config=Engine, DefaultConfig)
class UOscSettings : public UObject
{
GENERATED_BODY()
public:
/// Default constructor
UOscSettings();
/// Hot reload constructor
UOscSettings(FVTableHelper & helper);
/**
* Specify the [address:]port to listen to.
*
* e.g.
* - "8000" listen to messages from any sender on port 8000. [default]
* - "224.0.0.100:8000" listen multi-cast messages of group 224.0.0.100 on port 8000.
* - "192.168.0.1:8000" listen messages addressed specifically to 192.168.0.1 on port 8000, useful if there are several addresses for this machine.
*/
UPROPERTY(Config, EditAnywhere, Category=Receive)
FString ReceiveFrom;
UPROPERTY(Config, EditAnywhere, Category=Send)
TArray<FString> SendTargets;
/**
* List of the messages treated as inputs.
*
* Every entry adds a key in the input mapping project setting.
* e.g. "/position/x" -> "OSC_position_x"
*/
UPROPERTY(Config, EditAnywhere, Category=Input)
TArray<FString> Inputs;
UPROPERTY(Config, EditAnywhere, Category=Network)
bool MulticastLoopback;
public:
void InitSendTargets();
int32 GetOrAddSendTarget(const FString & ip_port);
void Send(const uint8 *buffer, int32 length, int32 targetIndex);
void ClearKeyInputs(UOscDispatcher & dispatcher);
void UpdateKeyInputs(UOscDispatcher & dispatcher);
public:
/**
* @brief Parse "8000" and "192.168.0.12" to IP and port values.
* @return true if succeed
*/
static bool Parse(const FString & ip_port, FIPv4Address * address, uint32_t * port);
private:
int32 AddSendTarget(const FString & ip_port);
private:
TSharedRef<FSocket> _sendSocket;
TArray<TSharedRef<FInternetAddr>> _sendAddresses;
TMap<FString, int32> _sendAddressesIndex;
TArray<std::unique_ptr<OscReceiverInputKey>> _keyReceivers;
};
@@ -1,260 +0,0 @@
#include "OscPrivatePCH.h"
#include "OscDispatcher.h"
#include "OscReceiverInterface.h"
#include "oscpack/osc/OscReceivedElements.h"
UOscDispatcher::UOscDispatcher()
: _listening(FIPv4Address(0), 0),
_socket(nullptr),
_socketReceiver(nullptr),
_pendingMessages(1024), // arbitrary max message count per frame
_taskSpawned(0)
{
}
UOscDispatcher::UOscDispatcher(FVTableHelper & helper)
: _pendingMessages(0)
{
// Does not need to be a valid object.
}
UOscDispatcher * UOscDispatcher::Get()
{
return UOscDispatcher::StaticClass()->GetDefaultObject<UOscDispatcher>();
}
void UOscDispatcher::Listen(FIPv4Address address, uint32_t port, bool multicastLoopback)
{
if(_listening != std::make_pair(address, port))
{
Stop();
FUdpSocketBuilder builder(TEXT("OscListener"));
builder.BoundToPort(port);
if(address.IsMulticastAddress())
{
builder.JoinedToGroup(address);
if(multicastLoopback)
{
builder.WithMulticastLoopback();
}
}
else
{
builder.BoundToAddress(address);
}
_socket = builder.Build();
if(_socket)
{
_socketReceiver = new FUdpSocketReceiver(_socket, FTimespan::FromMilliseconds(100), TEXT("OSCListener"));
_socketReceiver->OnDataReceived().BindUObject(this, &UOscDispatcher::Callback);
_socketReceiver->Start();
_listening = std::make_pair(address, port);
UE_LOG(LogOSC, Display, TEXT("Listen to port %d"), port);
}
else
{
UE_LOG(LogOSC, Warning, TEXT("Cannot listen port %d"), port);
}
}
}
void UOscDispatcher::Stop()
{
UE_LOG(LogOSC, Display, TEXT("Stop listening"));
delete _socketReceiver;
_socketReceiver = nullptr;
if(_socket)
{
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(_socket);
_socket = nullptr;
}
_listening = std::make_pair(FIPv4Address(0), 0);
}
void UOscDispatcher::RegisterReceiver(IOscReceiverInterface * receiver)
{
FScopeLock ScopeLock(&_receiversMutex);
_receivers.AddUnique(receiver);
}
void UOscDispatcher::UnregisterReceiver(IOscReceiverInterface * receiver)
{
FScopeLock ScopeLock(&_receiversMutex);
_receivers.Remove(receiver);
}
static void SendMessage(TCircularQueue<std::tuple<FName, TArray<FOscDataElemStruct>, FIPv4Address>> & _pendingMessages,
const osc::ReceivedMessage & message,
const FIPv4Address & senderIp)
{
if(message.State() != osc::SUCCESS)
{
UE_LOG(LogOSC, Warning, TEXT("OSC Received Message Error: %s"), osc::errorString(message.State()));
return;
}
const FName address(message.AddressPattern());
TArray<FOscDataElemStruct> data;
const auto argBegin = message.ArgumentsBegin();
const auto argEnd = message.ArgumentsEnd();
for(auto it = argBegin; it != argEnd; ++it)
{
FOscDataElemStruct elem;
if(it->IsFloat())
{
elem.SetFloat(it->AsFloatUnchecked());
}
else if(it->IsDouble())
{
elem.SetFloat(it->AsDoubleUnchecked());
}
else if(it->IsInt32())
{
elem.SetInt(it->AsInt32Unchecked());
}
else if(it->IsInt64())
{
elem.SetInt(it->AsInt64Unchecked());
}
else if(it->IsBool())
{
osc::Errors error = osc::SUCCESS;
elem.SetBool(it->AsBoolUnchecked(error));
check(error == osc::SUCCESS);
}
else if(it->IsString())
{
elem.SetString(FName(it->AsStringUnchecked()));
}
else if(it->IsBlob())
{
const void* buffer;
osc::osc_bundle_element_size_t size;
osc::Errors error = osc::SUCCESS;
it->AsBlobUnchecked(buffer, size, error);
TArray<uint8> blob;
if(size && !error)
{
blob.SetNumUninitialized(size);
FMemory::Memcpy(blob.GetData(), buffer, size);
}
else if(error)
{
UE_LOG(LogOSC, Warning, TEXT("OSC Received Message Error: %s"), osc::errorString(error));
}
elem.SetBlob(std::move(blob));
}
data.Add(elem);
}
// save it in pending messages
const auto added = _pendingMessages.Enqueue(std::make_tuple(address, data, senderIp));
// the circular buffer may be full.
if(!added)
{
UE_LOG(LogOSC, Warning, TEXT("Circular Buffer Full: Message Ignored"));
}
}
static void SendBundle(TCircularQueue<std::tuple<FName, TArray<FOscDataElemStruct>, FIPv4Address>> & _pendingMessages,
const osc::ReceivedBundle & bundle,
const FIPv4Address & senderIp)
{
if(bundle.State() != osc::SUCCESS)
{
UE_LOG(LogOSC, Warning, TEXT("OSC Received Bundle Error: %s"), osc::errorString(bundle.State()));
return;
}
const auto begin = bundle.ElementsBegin();
const auto end = bundle.ElementsEnd();
for(auto it = begin; it != end; ++it)
{
if(it->IsBundle())
{
SendBundle(_pendingMessages, osc::ReceivedBundle(*it), senderIp);
}
else
{
SendMessage(_pendingMessages, osc::ReceivedMessage(*it), senderIp);
}
}
}
void UOscDispatcher::Callback(const FArrayReaderPtr& data, const FIPv4Endpoint& endpoint)
{
const osc::ReceivedPacket packet((const char *)data->GetData(), data->Num());
if(packet.State() != osc::SUCCESS)
{
UE_LOG(LogOSC, Warning, TEXT("OSC Received Packet Error: %s"), osc::errorString(packet.State()));
return;
}
if(packet.IsBundle())
{
SendBundle(_pendingMessages, osc::ReceivedBundle(packet), endpoint.Address);
}
else
{
SendMessage(_pendingMessages, osc::ReceivedMessage(packet), endpoint.Address);
}
// Set a single callback in the main thread per frame.
if(!_pendingMessages.IsEmpty() && !FPlatformAtomics::InterlockedCompareExchange(&_taskSpawned, 1, 0))
{
check(_taskSpawned == 1);
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
FSimpleDelegateGraphTask::FDelegate::CreateUObject(this, &UOscDispatcher::CallbackMainThread),
TStatId(),
nullptr,
ENamedThreads::GameThread);
}
#if !NO_LOGGING
// Log received packet
if(!LogOSC.IsSuppressed(ELogVerbosity::Verbose))
{
const auto encoded = FBase64::Encode(*data);
UE_LOG(LogOSC, Verbose, TEXT("Received: %s"), *encoded);
}
#endif
}
void UOscDispatcher::CallbackMainThread()
{
// Release before dequeue.
// If it was released after dequeue, when a message arrives after the while
// loop and before the release, it would not be processed.
check(_taskSpawned == 1);
FPlatformAtomics::InterlockedCompareExchange(&_taskSpawned, 0, 1);
FScopeLock ScopeLock(&_receiversMutex);
std::tuple<FName, TArray<FOscDataElemStruct>, FIPv4Address> message;
while(_pendingMessages.Dequeue(message))
{
const FIPv4Address & senderIp = std::get<2>(message);
FString senderIpStr = FString::Printf(TEXT("%i.%i.%i.%i"), senderIp.A, senderIp.B, senderIp.C, senderIp.D);
for(auto receiver : _receivers)
{
receiver->SendEvent(std::get<0>(message), std::get<1>(message), senderIpStr);
}
}
}
void UOscDispatcher::BeginDestroy()
{
Stop();
Super::BeginDestroy();
}
@@ -1,57 +0,0 @@
#pragma once
#include "OscDataElemStruct.h"
#include "OscDispatcher.generated.h"
struct IOscReceiverInterface;
class FSocket;
class FUdpSocketReceiver;
/// Singleton that dispatches the OSC messages to listeners.
UCLASS()
class UOscDispatcher : public UObject
{
GENERATED_BODY()
friend class FOscModule;
void Listen(FIPv4Address address, uint32_t port, bool multicastLoopback);
void Stop();
public:
/// Default constructor
UOscDispatcher();
/// Hot reload constructor
UOscDispatcher(FVTableHelper & helper);
/// Get the unique instance
///
/// The instance is the UObject default instance.
static UOscDispatcher * Get();
/// Add the receiver in the listeners list
void RegisterReceiver(IOscReceiverInterface * receiver);
/// Remove the receiver in the listeners list
void UnregisterReceiver(IOscReceiverInterface * receiver);
private:
void Callback(const FArrayReaderPtr& data, const FIPv4Endpoint&);
void CallbackMainThread();
void BeginDestroy() override;
private:
TArray<IOscReceiverInterface *> _receivers;
std::pair<FIPv4Address, uint32_t> _listening;
FSocket * _socket;
FUdpSocketReceiver * _socketReceiver;
TCircularQueue<std::tuple<FName, TArray<FOscDataElemStruct>, FIPv4Address>> _pendingMessages;
int32 _taskSpawned;
/// Protects _receivers
FCriticalSection _receiversMutex;
};
@@ -1,35 +0,0 @@
#include "OscPrivatePCH.h"
#include "OscReceiverActor.h"
#include "OscDispatcher.h"
AOscReceiverActor::AOscReceiverActor()
: _listener(this)
{
auto instance = UOscDispatcher::Get();
if (instance && !HasAnyFlags(RF_ClassDefaultObject))
{
instance->RegisterReceiver(&_listener);
UE_LOG(LogOSC, Verbose, TEXT("Registering actor %s"), *GetName());
}
}
AOscReceiverActor::AOscReceiverActor(FVTableHelper & helper)
: _listener(this)
{
// Does not need to be a valid object.
}
void AOscReceiverActor::BeginDestroy()
{
auto instance = UOscDispatcher::Get();
if (instance && !HasAnyFlags(RF_ClassDefaultObject))
{
instance->UnregisterReceiver(&_listener);
UE_LOG(LogOSC, Verbose, TEXT("Unregistering actor %s"), *GetName());
}
Super::BeginDestroy();
}
@@ -1,44 +0,0 @@
#pragma once
#include "GameFramework/Actor.h"
#include "OscReceiverInterface.h"
#include "OscDataElemStruct.h"
#include "OscReceiverActor.generated.h"
UCLASS(ClassGroup=OSC)
class AOscReceiverActor : public AActor
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, Category=OSC)
FString AddressFilter;
UFUNCTION(BlueprintImplementableEvent, Category=OSC)
void OnOscReceived(const FName & Address, const TArray<FOscDataElemStruct> & Data, const FString & SenderIp);
public:
AOscReceiverActor();
/// Hot reload constructor
AOscReceiverActor(FVTableHelper & helper);
const FString & GetAddressFilter() const
{
return AddressFilter;
}
void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data, const FString & SenderIp)
{
OnOscReceived(Address, Data, SenderIp);
}
private:
void BeginDestroy() override;
private:
BasicOscReceiver<AOscReceiverActor> _listener;
};
@@ -1,60 +0,0 @@
#include "OscPrivatePCH.h"
#include "OscReceiverComponent.h"
#include "OscDispatcher.h"
UOscReceiverComponent::UOscReceiverComponent()
: _listener(this)
{
}
UOscReceiverComponent::UOscReceiverComponent(FVTableHelper & helper)
: _listener(this)
{
// Does not need to be a valid object.
}
void UOscReceiverComponent::OnRegister()
{
Super::OnRegister();
auto instance = UOscDispatcher::Get();
if (instance &&
!HasAnyFlags(RF_ClassDefaultObject) &&
(!GetOwner() || !GetOwner()->HasAnyFlags(RF_ClassDefaultObject)))
{
instance->RegisterReceiver(&_listener);
if(GetOwner())
{
UE_LOG(LogOSC, Verbose, TEXT("Registering component %s of %s"), *GetName(), *GetOwner()->GetName());
}
else
{
UE_LOG(LogOSC, Verbose, TEXT("Registering component %s"), *GetName());
}
}
}
void UOscReceiverComponent::OnUnregister()
{
auto instance = UOscDispatcher::Get();
if (instance &&
!HasAnyFlags(RF_ClassDefaultObject) &&
(!GetOwner() || !GetOwner()->HasAnyFlags(RF_ClassDefaultObject)))
{
instance->UnregisterReceiver(&_listener);
if(GetOwner())
{
UE_LOG(LogOSC, Verbose, TEXT("Unregistering component %s of %s"), *GetName(), *GetOwner()->GetName());
}
else
{
UE_LOG(LogOSC, Verbose, TEXT("Unregistering component %s"), *GetName());
}
}
Super::OnUnregister();
}
@@ -1,50 +0,0 @@
#pragma once
#include "Components/ActorComponent.h"
#include "OscReceiverInterface.h"
#include "OscDataElemStruct.h"
#include "OscReceiverComponent.generated.h"
// declare the OnOscReceived event type
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FComponentOscReceivedSignature, const FName &, Address, const TArray<FOscDataElemStruct> &, Data, const FString &, SenderIp);
UCLASS(ClassGroup=OSC, meta = (BlueprintSpawnableComponent))
class UOscReceiverComponent : public UActorComponent
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, Category=OSC)
FString AddressFilter;
UPROPERTY(BlueprintAssignable, Category=OSC)
FComponentOscReceivedSignature OnOscReceived;
public:
UOscReceiverComponent();
/// Hot reload constructor
UOscReceiverComponent(FVTableHelper & helper);
const FString & GetAddressFilter() const
{
return AddressFilter;
}
void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data, const FString & SenderIp)
{
OnOscReceived.Broadcast(Address, Data, SenderIp);
}
private:
void OnRegister() override;
void OnUnregister() override;
private:
BasicOscReceiver<UOscReceiverComponent> _listener;
};
@@ -1,62 +0,0 @@
#include "OscPrivatePCH.h"
#include "OscReceiverInputKey.h"
#include "OscDispatcher.h"
#include "SlateBasics.h"
OscReceiverInputKey::OscReceiverInputKey(const FString &address)
: _address(address),
_addressName(*address)
{
char buffer[512]; // address truncated after 500 chars.
const auto length = sprintf(buffer, "OSC%.500s", StringCast<ANSICHAR>(*address).Get());
// replace '/' by '_' because '/' is not a valid FKey character.
for(int i=0; i!=length; ++i)
{
if(buffer[i] == '/')
{
buffer[i] = '_';
}
}
_key = FName(buffer);
RegisterKey();
}
void OscReceiverInputKey::RegisterKey() const
{
if(!_address.IsEmpty() && !EKeys::GetKeyDetails(_key).IsValid())
{
EKeys::AddKey(FKeyDetails(_key,
FText::FromString(_key.ToString()),
FKeyDetails::FloatAxis));
}
}
void OscReceiverInputKey::SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data, const FString & SenderIp)
{
if(Address != _addressName)
{
return;
}
auto & app = FSlateApplication::Get();
const auto value = Data.Num() ? Data[0].GetValue<float>() : 0.f;
FKeyEvent keyEvent(_key, app.GetModifierKeys(), 0, false, 0, 0);
if(value < 0.5f)
{
app.ProcessKeyDownEvent(keyEvent);
}
else
{
app.ProcessKeyUpEvent(keyEvent);
}
FAnalogInputEvent axisEvent(_key, app.GetModifierKeys(), 0, false, 0, 0, value);
app.ProcessAnalogInputEvent(axisEvent);
}
@@ -1,33 +0,0 @@
#pragma once
#include "InputCoreTypes.h"
#include "OscReceiverInterface.h"
#include "OscDataElemStruct.h"
class OscReceiverInputKey : public IOscReceiverInterface
{
public:
OscReceiverInputKey(const FString & address);
OscReceiverInputKey(const OscReceiverInputKey &) = delete;
OscReceiverInputKey& operator=(const OscReceiverInputKey &) = delete;
private:
/// Adds the custom input key to the Slate application.
void RegisterKey() const;
const FString & GetAddressFilter() const override
{
return _address;
}
void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data, const FString & SenderIp) override;
private:
FString _address;
FName _addressName;
FKey _key;
};
@@ -1,34 +0,0 @@
#pragma once
#include "OscDataElemStruct.h"
/// Base class to receive OSC messages.
struct IOscReceiverInterface
{
virtual ~IOscReceiverInterface() {}
virtual const FString & GetAddressFilter() const = 0;
virtual void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data, const FString & SenderIp) = 0;
};
/// Forward calls to an impl object.
template <class T>
struct BasicOscReceiver : IOscReceiverInterface
{
T * const _impl;
BasicOscReceiver(T * impl) : _impl(impl)
{
}
const FString & GetAddressFilter() const final
{
return _impl->GetAddressFilter();
}
void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data, const FString & SenderIp) final
{
_impl->SendEvent(Address, Data, SenderIp);
}
};
-13
View File
@@ -1,13 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
using UnrealBuildTool;
using System.Collections.Generic;
public class OscDemoTarget : TargetRules
{
public OscDemoTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Game;
ExtraModuleNames.AddRange( new string[] { "OscDemo" } );
}
}
@@ -1,26 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
using UnrealBuildTool;
public class OscDemo : ModuleRules
{
public OscDemo(ReadOnlyTargetRules Target) : base(Target)
{
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PrivateDependencyModuleNames.AddRange(new string[] { });
// Uncomment if you are using Slate UI
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
// Uncomment if you are using online features
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
// if ((Target.Platform == UnrealTargetPlatform.Win32) || (Target.Platform == UnrealTargetPlatform.Win64))
// {
// if (UEBuildConfiguration.bCompileSteamOSS == true)
// {
// DynamicallyLoadedModuleNames.Add("OnlineSubsystemSteam");
// }
// }
}
}
@@ -1,5 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "OscDemo.h"
IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, OscDemo, "OscDemo" );
@@ -1,6 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "Engine.h"
@@ -1,8 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "OscDemo.h"
#include "OscDemoGameMode.h"
@@ -1,19 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameFramework/GameMode.h"
#include "OscDemoGameMode.generated.h"
/**
*
*/
UCLASS()
class OSCDEMO_API AOscDemoGameMode : public AGameMode
{
GENERATED_BODY()
};
@@ -1,13 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
using UnrealBuildTool;
using System.Collections.Generic;
public class OscDemoEditorTarget : TargetRules
{
public OscDemoEditorTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Editor;
ExtraModuleNames.AddRange(new string[] { "OscDemo" });
}
}
Binary file not shown.