init
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
#include "system/WindowsUtilities.h"
|
||||
#if defined TARGET_OS_Windows
|
||||
#include "m_ConverterUtf8.h"
|
||||
#include <ShellAPI.h>
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
namespace System {
|
||||
|
||||
// Load a library in a matter compliant with non-ascii path
|
||||
// returns the eventual error code
|
||||
void* WindowsUtilities::utf16CompliantLoadLibrary(const char* path, const HANDLE file, const DWORD flags)
|
||||
{
|
||||
//const HMODULE hModule = ::LoadLibraryEx(path, file, flags); // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR|LOAD_LIBRARY_DEFAULT_DIRS);
|
||||
return ::LoadLibraryEx(path, file, flags); // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR|LOAD_LIBRARY_DEFAULT_DIRS);
|
||||
}
|
||||
|
||||
BOOL WindowsUtilities::utf16CompliantSetEnvironmentVariable(const char* name, const char* value) { return SetEnvironmentVariable(name, value); }
|
||||
|
||||
// Load a library in a matter compliant with non-ascii path
|
||||
// returns the eventual error code
|
||||
BOOL WindowsUtilities::utf16CompliantCreateProcess(char* applicationName, char* commandLine, LPSECURITY_ATTRIBUTES processAttributes,
|
||||
LPSECURITY_ATTRIBUTES threadAttributes, const BOOL inheritHandles, const DWORD creationFlags,
|
||||
LPVOID environment, char* currentDirectory, LPSTARTUPINFO startupInfo,
|
||||
LPPROCESS_INFORMATION processInformation)
|
||||
{
|
||||
return CreateProcess(applicationName, const_cast<char*>(commandLine), processAttributes, threadAttributes,
|
||||
inheritHandles, creationFlags, environment, currentDirectory, startupInfo, processInformation);
|
||||
}
|
||||
|
||||
// Load a library in a matter compliant with non-ascii path
|
||||
// returns the eventual error code
|
||||
HINSTANCE WindowsUtilities::utf16CompliantShellExecute(HWND hwnd, LPCTSTR operation, LPCTSTR file, LPCTSTR parameters, LPCTSTR directory, const INT nShowCmd)
|
||||
{
|
||||
return ShellExecute(hwnd, operation, file, parameters, directory, nShowCmd);
|
||||
}
|
||||
|
||||
} // namespace System
|
||||
#endif // TARGET_OS_Windows
|
||||
@@ -0,0 +1,101 @@
|
||||
#include "system/ovCChrono.h"
|
||||
#include "system/ovCTime.h"
|
||||
|
||||
namespace System {
|
||||
|
||||
CChrono::~CChrono()
|
||||
{
|
||||
delete [] m_stepInTime;
|
||||
delete [] m_stepOutTime;
|
||||
}
|
||||
|
||||
bool CChrono::reset(const size_t nStep)
|
||||
{
|
||||
if (!nStep) { return false; }
|
||||
|
||||
uint64_t* stepInTime = new uint64_t[nStep + 1];
|
||||
uint64_t* stepOutTime = new uint64_t[nStep + 1];
|
||||
if (!stepInTime || !stepOutTime)
|
||||
{
|
||||
delete [] stepInTime;
|
||||
delete [] stepOutTime;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i <= nStep; ++i)
|
||||
{
|
||||
stepInTime[i] = 0;
|
||||
stepOutTime[i] = 0;
|
||||
}
|
||||
|
||||
delete [] m_stepInTime;
|
||||
delete [] m_stepOutTime;
|
||||
m_stepInTime = stepInTime;
|
||||
m_stepOutTime = stepOutTime;
|
||||
|
||||
m_nStep = nStep;
|
||||
m_stepIdx = 0;
|
||||
m_isInStep = false;
|
||||
m_hasNewEstimation = false;
|
||||
|
||||
m_totalStepInTime = 0;
|
||||
m_totalStepOutTime = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CChrono::stepIn()
|
||||
{
|
||||
if (m_isInStep || !m_nStep) { return false; }
|
||||
|
||||
m_isInStep = !m_isInStep;
|
||||
|
||||
m_stepInTime[m_stepIdx] = Time::zgetTime();
|
||||
if (m_stepIdx == m_nStep)
|
||||
{
|
||||
m_totalStepInTime = 0;
|
||||
m_totalStepOutTime = 0;
|
||||
for (size_t i = 0; i < m_nStep; ++i)
|
||||
{
|
||||
m_totalStepInTime += m_stepOutTime[i] - m_stepInTime[i];
|
||||
m_totalStepOutTime += m_stepInTime[i + 1] - m_stepOutTime[i];
|
||||
}
|
||||
m_stepInTime[0] = m_stepInTime[m_nStep];
|
||||
m_stepIdx = 0;
|
||||
m_hasNewEstimation = true;
|
||||
}
|
||||
else { m_hasNewEstimation = false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CChrono::stepOut()
|
||||
{
|
||||
if (!m_isInStep || !m_nStep) { return false; }
|
||||
|
||||
m_isInStep = !m_isInStep;
|
||||
|
||||
m_stepOutTime[m_stepIdx] = Time::zgetTime();
|
||||
m_stepIdx++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t CChrono::getTotalStepInDuration() const { return m_totalStepInTime; }
|
||||
uint64_t CChrono::getTotalStepOutDuration() const { return m_totalStepOutTime; }
|
||||
uint64_t CChrono::getAverageStepInDuration() const { return m_nStep ? this->getTotalStepInDuration() / m_nStep : 0; }
|
||||
uint64_t CChrono::getAverageStepOutDuration() const { return m_nStep ? this->getTotalStepOutDuration() / m_nStep : 0; }
|
||||
|
||||
double CChrono::getStepInPercentage() const
|
||||
{
|
||||
const uint64_t totalStepDuration = (this->getTotalStepInDuration() + this->getTotalStepOutDuration());
|
||||
return totalStepDuration ? (this->getTotalStepInDuration() * 100.0) / totalStepDuration : 0;
|
||||
}
|
||||
|
||||
double CChrono::getStepOutPercentage() const
|
||||
{
|
||||
const uint64_t totalStepDuration = (this->getTotalStepOutDuration() + this->getTotalStepInDuration());
|
||||
return totalStepDuration ? (this->getTotalStepOutDuration() * 100.0) / totalStepDuration : 0;
|
||||
}
|
||||
|
||||
} // namespace System
|
||||
@@ -0,0 +1,396 @@
|
||||
#include "system/ovCDynamicModule.h"
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
#include <system/WindowsUtilities.h> // Allowed to use utf8_to_utf16 function for os that use utf16
|
||||
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
namespace System {
|
||||
|
||||
static const std::map<CDynamicModule::ELogErrorCodes, std::string> ERROR_MAP =
|
||||
{
|
||||
{ CDynamicModule::LogErrorCodes_ModuleAlreadyLoaded, "A module is already loaded." },
|
||||
{ CDynamicModule::LogErrorCodes_NoModuleLoaded, "No module loaded." },
|
||||
{ CDynamicModule::LogErrorCodes_FilenameEmpty, "The filename is empty." },
|
||||
{ CDynamicModule::LogErrorCodes_FolderPathInvalid, "The folder path is invalid." },
|
||||
{ CDynamicModule::LogErrorCodes_RegistryQueryFailed, "The registry query is invalid." },
|
||||
{ CDynamicModule::LogErrorCodes_UnloadModuleFailed, "Fail to unload the module." },
|
||||
{ CDynamicModule::LogErrorCodes_FailToLoadModule, "Fail to load the module." },
|
||||
{ CDynamicModule::LogErrorCodes_InvalidSymbol, "The symbol is invalid." },
|
||||
{ CDynamicModule::LogErrorCodes_ModuleNotFound, "Module not found." }
|
||||
};
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
static std::vector<std::string> split(char* str, const char* delim)
|
||||
{
|
||||
char* token = strtok(str, delim);
|
||||
|
||||
std::vector<std::string> result;
|
||||
|
||||
while (token != nullptr)
|
||||
{
|
||||
result.push_back(token);
|
||||
token = strtok(nullptr, delim);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string formatWindowsError(const DWORD code)
|
||||
{
|
||||
LPTSTR text;
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | // use system message tables to retrieve error text
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | // allocate buffer on local heap for error text
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, // Important! will fail otherwise, since we're not (and CANNOT) pass insertion parameters
|
||||
nullptr, // unused with FORMAT_MESSAGE_FROM_SYSTEM
|
||||
code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
LPTSTR(&text), // output
|
||||
0, // minimum size for output buffer
|
||||
nullptr
|
||||
); // arguments - see note
|
||||
|
||||
return std::string(text);
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* CDynamicModule::getErrorString(size_t errorCode)
|
||||
{
|
||||
if (ERROR_MAP.count(ELogErrorCodes(errorCode)) == 0) { return "Invalid error code"; }
|
||||
return ERROR_MAP.at(ELogErrorCodes(errorCode)).c_str();
|
||||
}
|
||||
|
||||
const char* CDynamicModule::getErrorDetails() const { return &m_ErrorDetails[0]; }
|
||||
size_t CDynamicModule::getLastError() const { return m_ErrorCode; }
|
||||
|
||||
CDynamicModule::CDynamicModule()
|
||||
: m_ErrorMode(m_ErrorModeNull), m_ErrorCode(LogErrorCodes_NoError)
|
||||
{
|
||||
strcpy(m_ErrorDetails, "");
|
||||
strcpy(m_Filename, "");
|
||||
}
|
||||
|
||||
CDynamicModule::~CDynamicModule() {}
|
||||
|
||||
// --------------------------------------
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
bool CDynamicModule::loadFromExisting(const char* modulePath, const char* symbolNameCheck)
|
||||
{
|
||||
if (m_Handle)
|
||||
{
|
||||
this->setError(LogErrorCodes_ModuleAlreadyLoaded, "Module [" + std::string(m_Filename) + "] is already loaded");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Handle = ::GetModuleHandle(modulePath);
|
||||
|
||||
if (m_Handle == nullptr)
|
||||
{
|
||||
this->setError(LogErrorCodes_FailToLoadModule, "Windows error: " + formatWindowsError(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (symbolNameCheck != nullptr)
|
||||
{
|
||||
if (GetProcAddress(HMODULE(m_Handle), symbolNameCheck) == nullptr)
|
||||
{
|
||||
this->unload();
|
||||
this->setError(LogErrorCodes_InvalidSymbol, "Windows error: " + formatWindowsError(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(m_Filename, modulePath);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CDynamicModule::loadFromPath(const char* modulePath, const char* symbolNameCheck)
|
||||
{
|
||||
if (m_Handle)
|
||||
{
|
||||
this->setError(LogErrorCodes_ModuleAlreadyLoaded, "Module [" + std::string(m_Filename) + "] is already loaded");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify empty filename
|
||||
if (modulePath == nullptr || (modulePath != nullptr && modulePath[0] == '\0'))
|
||||
{
|
||||
this->setError(LogErrorCodes_FilenameEmpty);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
|
||||
if (m_ErrorMode == m_ErrorModeNull)
|
||||
{
|
||||
const UINT mode = SetErrorMode(UINT(m_ErrorModeNull));
|
||||
SetErrorMode(mode);
|
||||
}
|
||||
else { SetErrorMode(UINT(m_ErrorMode)); }
|
||||
|
||||
m_Handle = WindowsUtilities::utf16CompliantLoadLibrary(modulePath, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
|
||||
if (m_Handle == nullptr)
|
||||
{
|
||||
this->setError(LogErrorCodes_FailToLoadModule, "Fail to load [" + std::string(modulePath) + "]. Windows error:" + formatWindowsError(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (symbolNameCheck != nullptr)
|
||||
{
|
||||
if (GetProcAddress(HMODULE(m_Handle), symbolNameCheck) == nullptr)
|
||||
{
|
||||
this->unload();
|
||||
this->setError(LogErrorCodes_InvalidSymbol,
|
||||
"Symbol invalid: [" + std::string(symbolNameCheck) + "]. Windows error: " + formatWindowsError(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
m_Handle = ::dlopen(modulePath, RTLD_LAZY|RTLD_GLOBAL);
|
||||
|
||||
if (m_Handle == nullptr)
|
||||
{
|
||||
this->setError(LogErrorCodes_FailToLoadModule);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(symbolNameCheck != nullptr)
|
||||
{
|
||||
if(::dlsym(m_Handle, symbolNameCheck) == nullptr)
|
||||
{
|
||||
char* error = ::dlerror();
|
||||
|
||||
if(error) { this->setError(LogErrorCodes_InvalidSymbol, "Error: " + std::string(error)); }
|
||||
else { this->setError(LogErrorCodes_InvalidSymbol); }
|
||||
|
||||
::dlclose(m_Handle);
|
||||
m_Handle = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
strcpy(m_Filename, modulePath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
bool CDynamicModule::loadFromKnownPath(const int standardPath, const char* modulePath, const char* symbolNameCheck)
|
||||
{
|
||||
if (m_Handle)
|
||||
{
|
||||
this->setError(LogErrorCodes_ModuleAlreadyLoaded, "Module [" + std::string(m_Filename) + "] is already loaded");
|
||||
return false;
|
||||
}
|
||||
|
||||
char dllPath[MAX_PATH];
|
||||
|
||||
const HRESULT result = ::SHGetFolderPath(nullptr, standardPath, nullptr, SHGFP_TYPE_CURRENT, dllPath);
|
||||
|
||||
if (result != S_OK)
|
||||
{
|
||||
this->setError(LogErrorCodes_FolderPathInvalid, "Windows error code: " + std::to_string(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
strcat(dllPath, "\\");
|
||||
strcat(dllPath, modulePath);
|
||||
return loadFromPath(dllPath, symbolNameCheck); // Error set in the loadFromPath function
|
||||
}
|
||||
|
||||
bool CDynamicModule::loadFromEnvironment(const char* environmentPath, const char* modulePath, const char* symbolNameCheck)
|
||||
{
|
||||
if (m_Handle)
|
||||
{
|
||||
this->setError(LogErrorCodes_ModuleAlreadyLoaded, "Module [" + std::string(m_Filename) + "] is already loaded");
|
||||
return false;
|
||||
}
|
||||
|
||||
char* str = getenv(environmentPath);
|
||||
|
||||
if (str == nullptr)
|
||||
{
|
||||
this->setError(LogErrorCodes_EnvironmentVariableInvalid);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> paths = split(str, ";");
|
||||
|
||||
for (const std::string& path : paths) { if (loadFromPath((path + "\\" + modulePath).c_str(), symbolNameCheck)) { return true; } }
|
||||
|
||||
this->setError(LogErrorCodes_ModuleNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDynamicModule::loadFromRegistry(HKEY key, const char* registryPath, const char* registryKeyName, REGSAM samDesired, const char* modulePath,
|
||||
const char* symbolNameCheck)
|
||||
{
|
||||
char dllPath[MAX_PATH];
|
||||
DWORD size = sizeof(dllPath);
|
||||
dllPath[0] = '\0';
|
||||
|
||||
HKEY lKey = nullptr;
|
||||
|
||||
LONG result = RegOpenKeyEx(key, TEXT(registryPath), NULL, samDesired, &lKey);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
this->setError(LogErrorCodes_RegistryQueryFailed, "Fail to open registry key. Windows error code: " + std::to_string(result));
|
||||
RegCloseKey(lKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
result = ::RegQueryValueEx(lKey, registryKeyName, nullptr, nullptr, reinterpret_cast<unsigned char*>(dllPath), &size);
|
||||
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
strcat(dllPath, modulePath);
|
||||
return loadFromPath(dllPath, symbolNameCheck); // Error set in the loadFromPath function
|
||||
}
|
||||
this->setError(LogErrorCodes_RegistryQueryFailed, "Fail to query registry value. Windows error code: " + std::to_string(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDynamicModule::isModuleCompatible(const char* filePath, const int architecture)
|
||||
{
|
||||
IMAGE_NT_HEADERS headers;
|
||||
if (!getImageFileHeaders(filePath, headers)) { return false; } // Error set in the getImageFileHeaders function
|
||||
return headers.FileHeader.Machine == architecture;
|
||||
}
|
||||
#endif
|
||||
|
||||
// --------------------------------------
|
||||
|
||||
bool CDynamicModule::unload()
|
||||
{
|
||||
if (!m_Handle)
|
||||
{
|
||||
this->setError(LogErrorCodes_NoModuleLoaded);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the flag m_shouldFreeModule, set to true per default, is set to false,
|
||||
// the module is not unloaded.
|
||||
// This flag was first set for Enobio3G driver which dll freezes when unloaded
|
||||
if (!m_ShouldFreeModule) { return true; }
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
if (::FreeModule(reinterpret_cast<HMODULE>(m_Handle)) == 0)
|
||||
{
|
||||
this->setError(LogErrorCodes_UnloadModuleFailed, "Windows error code: " + formatWindowsError(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
if(::dlclose(m_Handle) != 0)
|
||||
{
|
||||
char* error = ::dlerror();
|
||||
if(error) { this->setError(LogErrorCodes_UnloadModuleFailed, "Error: " + std::string(error)); }
|
||||
else { this->setError(LogErrorCodes_UnloadModuleFailed); }
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
strcpy(m_Filename, "");
|
||||
m_Handle = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CDynamicModule::symbol_t CDynamicModule::getSymbolGeneric(const char* symbolName) const
|
||||
{
|
||||
symbol_t res = nullptr;
|
||||
|
||||
if (!m_Handle)
|
||||
{
|
||||
m_ErrorCode = LogErrorCodes_NoModuleLoaded;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (m_Handle)
|
||||
{
|
||||
#if defined TARGET_OS_Windows
|
||||
res = symbol_t(GetProcAddress(reinterpret_cast<HMODULE>(m_Handle), symbolName));
|
||||
|
||||
if (!res)
|
||||
{
|
||||
m_ErrorCode = LogErrorCodes_InvalidSymbol;
|
||||
return res;
|
||||
}
|
||||
|
||||
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
res = (CDynamicModule::symbol_t)::dlsym(m_Handle, symbolName);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
m_ErrorCode = LogErrorCodes_InvalidSymbol;
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef TARGET_OS_Windows
|
||||
bool CDynamicModule::getImageFileHeaders(const char* filename, IMAGE_NT_HEADERS& headers)
|
||||
{
|
||||
const HANDLE fileHandle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
if (fileHandle == INVALID_HANDLE_VALUE) { return false; }
|
||||
|
||||
const HANDLE imageHandle = CreateFileMapping(fileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
|
||||
if (imageHandle == nullptr)
|
||||
{
|
||||
CloseHandle(fileHandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
void* imagePtr = MapViewOfFile(imageHandle, FILE_MAP_READ, 0, 0, 0);
|
||||
|
||||
if (imagePtr == nullptr)
|
||||
{
|
||||
CloseHandle(imageHandle);
|
||||
CloseHandle(fileHandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
const PIMAGE_NT_HEADERS headersPtr = ImageNtHeader(imagePtr);
|
||||
|
||||
if (headersPtr == nullptr)
|
||||
{
|
||||
UnmapViewOfFile(imagePtr);
|
||||
CloseHandle(imageHandle);
|
||||
CloseHandle(fileHandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
headers = *headersPtr;
|
||||
|
||||
UnmapViewOfFile(imagePtr);
|
||||
CloseHandle(imageHandle);
|
||||
CloseHandle(fileHandle);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CDynamicModule::setError(const ELogErrorCodes errorCode, const std::string& details)
|
||||
{
|
||||
m_ErrorCode = errorCode;
|
||||
strcpy(m_ErrorDetails, details.c_str());
|
||||
}
|
||||
} // namespace System
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
*
|
||||
* @fixme This class could benefit from a serious overhaul, e.g. using randomness from some established library or C11.
|
||||
*
|
||||
* - Here Linear Congruential Generator is re-implemented to avoid third-party dependencies messing the up the rand() state.
|
||||
* This happened before when we used the global srand() / rand(). It made hard to make repeatable experiments on some
|
||||
* platforms. The generated randomness from the introduced home-made class is not super but it should be sufficient for
|
||||
* OpenViBE's present use-cases.
|
||||
*
|
||||
* Other notes
|
||||
*
|
||||
* - Due to generative process, values generated above L_RAND_MAX may not be dense (verify)
|
||||
* - randomIWithCeiling() may not be dense either
|
||||
*
|
||||
*/
|
||||
#include "system/ovCMath.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace System {
|
||||
|
||||
class RandomGenerator
|
||||
{
|
||||
size_t m_nextValue = 0;
|
||||
|
||||
public:
|
||||
static const size_t L_RAND_MAX = 2147483647; // (2^32)/2-1 == 2147483647 (0x7FFFFFFF)
|
||||
|
||||
explicit RandomGenerator(const size_t seed = 1) : m_nextValue(seed) {}
|
||||
|
||||
int rand()
|
||||
{
|
||||
// Pretty much C99 convention and parameters for a Linear Congruential Generator
|
||||
m_nextValue = (m_nextValue * 1103515245 + 12345) & L_RAND_MAX;
|
||||
return int(m_nextValue);
|
||||
}
|
||||
|
||||
void setSeed(const size_t seed) { m_nextValue = seed; }
|
||||
|
||||
size_t getSeed() const { return m_nextValue; }
|
||||
};
|
||||
|
||||
// Should be only accessed via Math:: calls defined below
|
||||
static RandomGenerator randomGenerator;
|
||||
|
||||
bool Math::initializeRandomMachine(const size_t randomSeed)
|
||||
{
|
||||
randomGenerator.setSeed(size_t(randomSeed));
|
||||
|
||||
// For safety, we install also the C++ basic random engine (it might be useg by dependencies, old code, etc)
|
||||
srand(uint32_t(randomSeed));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Math::randomI() { return size_t(random()); }
|
||||
size_t Math::randomWithCeiling(const size_t upperLimit) { return size_t(random0To1() * double(upperLimit)); }
|
||||
double Math::random0To1() { return double(randomGenerator.rand()) / double(RandomGenerator::L_RAND_MAX); }
|
||||
|
||||
uint64_t Math::random()
|
||||
{
|
||||
const uint64_t r1 = randomGenerator.rand();
|
||||
const uint64_t r2 = randomGenerator.rand();
|
||||
const uint64_t r3 = randomGenerator.rand();
|
||||
const uint64_t r4 = randomGenerator.rand();
|
||||
return (r1 << 24) ^ (r2 << 16) ^ (r3 << 8) ^ (r4);
|
||||
}
|
||||
|
||||
} // namespace System
|
||||
@@ -0,0 +1,169 @@
|
||||
#include "system/ovCMemory.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace System {
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
template <typename T>
|
||||
bool BigEndianToHost(const uint8_t* buffer, T* value)
|
||||
{
|
||||
if (!buffer || !value) { return false; }
|
||||
memset(value, 0, sizeof(T));
|
||||
for (size_t i = 0; i < sizeof(T); ++i) { ((uint8_t*)value)[i] = buffer[sizeof(T) - 1 - i]; }
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool LittleEndianToHost(const uint8_t* buffer, T* value)
|
||||
{
|
||||
if (!buffer || !value) { return false; }
|
||||
memset(value, 0, sizeof(T));
|
||||
for (size_t i = 0; i < sizeof(T); ++i) { ((uint8_t*)value)[i] = buffer[i]; }
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool HostToBigEndian(const T& value, uint8_t* buffer)
|
||||
{
|
||||
if (!buffer) { return false; }
|
||||
memset(buffer, 0, sizeof(T));
|
||||
for (size_t i = 0; i < sizeof(T); ++i) { buffer[i] = ((uint8_t*)&value)[sizeof(T) - 1 - i]; }
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool HostToLittleEndian(const T& value, uint8_t* buffer)
|
||||
{
|
||||
if (!buffer) { return false; }
|
||||
for (size_t i = 0; i < sizeof(T); ++i) { buffer[i] = uint8_t((value >> (i * 8)) & 0xff); }
|
||||
return true;
|
||||
}
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
bool Memory::hostToLittleEndian(const uint16_t value, uint8_t* buffer) { return HostToLittleEndian<uint16_t>(value, buffer); }
|
||||
bool Memory::hostToLittleEndian(const uint32_t value, uint8_t* buffer) { return HostToLittleEndian<uint32_t>(value, buffer); }
|
||||
bool Memory::hostToLittleEndian(const uint64_t value, uint8_t* buffer) { return HostToLittleEndian<uint64_t>(value, buffer); }
|
||||
bool Memory::hostToLittleEndian(const int16_t value, uint8_t* buffer) { return HostToLittleEndian<int16_t>(value, buffer); }
|
||||
bool Memory::hostToLittleEndian(const int value, uint8_t* buffer) { return HostToLittleEndian<int>(value, buffer); }
|
||||
bool Memory::hostToLittleEndian(const int64_t value, uint8_t* buffer) { return HostToLittleEndian<int64_t>(value, buffer); }
|
||||
|
||||
bool Memory::hostToLittleEndian(const float value, uint8_t* buffer)
|
||||
{
|
||||
uint32_t tmp;
|
||||
memcpy(&tmp, &value, sizeof(tmp));
|
||||
return hostToLittleEndian(tmp, buffer);
|
||||
}
|
||||
|
||||
bool Memory::hostToLittleEndian(const double value, uint8_t* buffer)
|
||||
{
|
||||
uint64_t tmp;
|
||||
memcpy(&tmp, &value, sizeof(tmp));
|
||||
return hostToLittleEndian(tmp, buffer);
|
||||
}
|
||||
|
||||
bool Memory::hostToLittleEndian(const long double /*value*/, uint8_t* /*buffer*/)
|
||||
{
|
||||
// $$$ TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
bool Memory::hostToBigEndian(const uint16_t value, uint8_t* buffer) { return HostToBigEndian<uint16_t>(value, buffer); }
|
||||
bool Memory::hostToBigEndian(const uint32_t value, uint8_t* buffer) { return HostToBigEndian<uint32_t>(value, buffer); }
|
||||
bool Memory::hostToBigEndian(const uint64_t value, uint8_t* buffer) { return HostToBigEndian<uint64_t>(value, buffer); }
|
||||
bool Memory::hostToBigEndian(const int16_t value, uint8_t* buffer) { return HostToBigEndian<int16_t>(value, buffer); }
|
||||
bool Memory::hostToBigEndian(const int value, uint8_t* buffer) { return HostToBigEndian<int>(value, buffer); }
|
||||
bool Memory::hostToBigEndian(const int64_t value, uint8_t* buffer) { return HostToBigEndian<int64_t>(value, buffer); }
|
||||
|
||||
bool Memory::hostToBigEndian(const float value, uint8_t* buffer)
|
||||
{
|
||||
uint32_t tmp;
|
||||
memcpy(&tmp, &value, sizeof(tmp));
|
||||
return hostToBigEndian(tmp, buffer);
|
||||
}
|
||||
|
||||
bool Memory::hostToBigEndian(const double value, uint8_t* buffer)
|
||||
{
|
||||
uint64_t tmp;
|
||||
memcpy(&tmp, &value, sizeof(tmp));
|
||||
return hostToBigEndian(tmp, buffer);
|
||||
}
|
||||
|
||||
bool Memory::hostToBigEndian(const long double /*value*/, uint8_t* /*buffer*/)
|
||||
{
|
||||
// $$$ TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
bool Memory::littleEndianToHost(const uint8_t* buffer, uint16_t* value) { return LittleEndianToHost<uint16_t>(buffer, value); }
|
||||
bool Memory::littleEndianToHost(const uint8_t* buffer, uint32_t* value) { return LittleEndianToHost<uint32_t>(buffer, value); }
|
||||
bool Memory::littleEndianToHost(const uint8_t* buffer, uint64_t* value) { return LittleEndianToHost<uint64_t>(buffer, value); }
|
||||
bool Memory::littleEndianToHost(const uint8_t* buffer, int16_t* value) { return LittleEndianToHost<int16_t>(buffer, value); }
|
||||
bool Memory::littleEndianToHost(const uint8_t* buffer, int* value) { return LittleEndianToHost<int>(buffer, value); }
|
||||
bool Memory::littleEndianToHost(const uint8_t* buffer, int64_t* value) { return LittleEndianToHost<int64_t>(buffer, value); }
|
||||
|
||||
bool Memory::littleEndianToHost(const uint8_t* buffer, float* value)
|
||||
{
|
||||
uint32_t tmp;
|
||||
const bool b = LittleEndianToHost<uint32_t>(buffer, &tmp);
|
||||
memcpy(value, &tmp, sizeof(float));
|
||||
return b;
|
||||
}
|
||||
|
||||
bool Memory::littleEndianToHost(const uint8_t* buffer, double* value)
|
||||
{
|
||||
uint64_t tmp;
|
||||
const bool b = LittleEndianToHost<uint64_t>(buffer, &tmp);
|
||||
memcpy(value, &tmp, sizeof(double));
|
||||
return b;
|
||||
}
|
||||
|
||||
bool Memory::littleEndianToHost(const uint8_t* /*buffer*/, long double* /*value*/)
|
||||
{
|
||||
// $$$ TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
bool Memory::bigEndianToHost(const uint8_t* buffer, uint16_t* value) { return BigEndianToHost<uint16_t>(buffer, value); }
|
||||
bool Memory::bigEndianToHost(const uint8_t* buffer, uint32_t* value) { return BigEndianToHost<uint32_t>(buffer, value); }
|
||||
bool Memory::bigEndianToHost(const uint8_t* buffer, uint64_t* value) { return BigEndianToHost<uint64_t>(buffer, value); }
|
||||
bool Memory::bigEndianToHost(const uint8_t* buffer, int16_t* value) { return BigEndianToHost<int16_t>(buffer, value); }
|
||||
bool Memory::bigEndianToHost(const uint8_t* buffer, int* value) { return BigEndianToHost<int>(buffer, value); }
|
||||
bool Memory::bigEndianToHost(const uint8_t* buffer, int64_t* value) { return BigEndianToHost<int64_t>(buffer, value); }
|
||||
|
||||
bool Memory::bigEndianToHost(const uint8_t* buffer, float* value)
|
||||
{
|
||||
uint32_t tmp;
|
||||
const bool b = BigEndianToHost<uint32_t>(buffer, &tmp);
|
||||
memcpy(value, &tmp, sizeof(float));
|
||||
return b;
|
||||
}
|
||||
|
||||
bool Memory::bigEndianToHost(const uint8_t* buffer, double* value)
|
||||
{
|
||||
uint64_t tmp;
|
||||
const bool b = BigEndianToHost<uint64_t>(buffer, &tmp);
|
||||
memcpy(value, &tmp, sizeof(double));
|
||||
return b;
|
||||
}
|
||||
|
||||
bool Memory::bigEndianToHost(const uint8_t* /*buffer*/, long double* /*value*/)
|
||||
{
|
||||
// $$$ TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace System
|
||||
@@ -0,0 +1,92 @@
|
||||
#include "system/ovCTime.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
|
||||
// \warning On Windows, avoid "using namespace System;" here as it may cause confusion with stuff coming from windows/boost
|
||||
// \note Support of C++11 steady clock:
|
||||
// - From GCC 4.8.1
|
||||
// - From Visual Studio 2015 (therefore a strategy is needed to handle Visual Studio 2013 version)
|
||||
|
||||
// time handling strategy selection
|
||||
// \note With officialy supported compilers and required boost version
|
||||
// it should never fallback in a OV_USE_SYSTEM case
|
||||
#if (defined(_MSC_VER) && _MSC_VER <= 1800 && defined(TARGET_HAS_Boost_Chrono))
|
||||
|
||||
#include <boost/chrono/config.hpp>
|
||||
|
||||
#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
|
||||
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
namespace Timelib = boost;
|
||||
|
||||
#else
|
||||
#error "Please use OpenViBE recommended version of Boost"
|
||||
#endif // BOOST_CHRONO_HAS_CLOCK_STEADY
|
||||
|
||||
#else // defined(_MSC_VER) && _MSC_VER <= 1800 && defined(TARGET_HAS_Boost_Chrono)
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
namespace Timelib = std;
|
||||
|
||||
#endif // defined(_MSC_VER) && _MSC_VER <= 1800 && defined(TARGET_HAS_Boost_Chrono)
|
||||
|
||||
using internal_clock = Timelib::chrono::steady_clock;
|
||||
// using internal_clock = chrono::high_resolution_clock;
|
||||
|
||||
namespace System {
|
||||
|
||||
bool Time::sleep(const size_t milliSeconds)
|
||||
{
|
||||
Timelib::this_thread::sleep_for(Timelib::chrono::milliseconds(milliSeconds));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Time::zsleep(const uint64_t seconds)
|
||||
{
|
||||
const uint32_t s = uint32_t(seconds >> 32);
|
||||
// zero the seconds with 0xFFFFFFFF, multiply to get the rest as fixed point microsec, then grab them (now in the 32 msbs)
|
||||
const uint64_t ms = ((seconds & 0xFFFFFFFFLL) * 1000000LL) >> 32;
|
||||
|
||||
const Timelib::chrono::microseconds duration = Timelib::chrono::seconds(s) + Timelib::chrono::microseconds(ms);
|
||||
Timelib::this_thread::sleep_for(duration);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t Time::zgetTimeRaw(const bool sinceFirstCall)
|
||||
{
|
||||
static bool initialized = false;
|
||||
static internal_clock::time_point start;
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
start = internal_clock::now();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
const internal_clock::time_point now = internal_clock::now();
|
||||
const internal_clock::duration elapsed = (sinceFirstCall ? now - start : now.time_since_epoch());
|
||||
const Timelib::chrono::microseconds elapsedMs = Timelib::chrono::duration_cast<Timelib::chrono::microseconds>(elapsed);
|
||||
|
||||
const uint64_t microsPerSecond = 1000ULL * 1000ULL;
|
||||
const uint64_t seconds = uint64_t(elapsedMs.count() / microsPerSecond);
|
||||
const uint64_t fraction = uint64_t(elapsedMs.count() % microsPerSecond);
|
||||
|
||||
// below in fraction part, scale [0,microsPerSecond-1] to 32bit integer range
|
||||
const uint64_t res = (seconds << 32) + fraction * (0xFFFFFFFFLL / (microsPerSecond - 1));
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Time::isClockSteady() { return internal_clock::is_steady; }
|
||||
|
||||
bool Time::checkResolution(const size_t milliSeconds)
|
||||
{
|
||||
assert(milliSeconds != 0);
|
||||
const auto resolution = double(internal_clock::period::num) / internal_clock::period::den;
|
||||
return (size_t(std::ceil(resolution * 1000)) <= milliSeconds);
|
||||
}
|
||||
|
||||
} // namespace System
|
||||
Reference in New Issue
Block a user