diff --git a/Config/OpenNI.ini b/Config/OpenNI.ini index a443fcb8..3375b84d 100644 --- a/Config/OpenNI.ini +++ b/Config/OpenNI.ini @@ -6,3 +6,9 @@ LogToFile=0 [Device] ;Override="" + +[Drivers] +; Location of the drivers specified by a relative path based on OpenNI's shared library or an absolute path. +; Path separator "/" can be used to be portable for any platforms. +; Default - OpenNI2/Drivers +;Repository=OpenNI2/Drivers diff --git a/Config/PS1080.ini b/Config/OpenNI2/Drivers/PS1080.ini similarity index 100% rename from Config/PS1080.ini rename to Config/OpenNI2/Drivers/PS1080.ini diff --git a/Redist/Redist.py b/Redist/Redist.py index ff01f42c..5c96ef1a 100755 --- a/Redist/Redist.py +++ b/Redist/Redist.py @@ -94,9 +94,12 @@ def compileAll(self): def copyOpenNI(self, where): # Copy config content to Redist - for r, d, f in os.walk('Config'): - for file in f: - shutil.copy(r+'/'+file, where) + for f in os.listdir('Config'): + p = 'Config/' + f; + if os.path.isdir(p): + shutil.copytree(p, where+'/'+f); + else: + shutil.copy(p, where+'/'+f); return diff --git a/Source/Core/OniContext.cpp b/Source/Core/OniContext.cpp index dab82203..1eb13b6d 100644 --- a/Source/Core/OniContext.cpp +++ b/Source/Core/OniContext.cpp @@ -22,13 +22,8 @@ #include "OniStreamFrameHolder.h" #include -static const char* ONI_CONFIGURATION_FILE = XN_FILE_LOCAL_DIR "OpenNI.ini"; -#if (XN_PLATFORM == XN_PLATFORM_WIN32) && (_M_X64) -static const char* ONI_ENV_VAR_DRIVERS_REPOSITORY = "OPENNI2_DRIVERS_PATH64"; -#else -static const char* ONI_ENV_VAR_DRIVERS_REPOSITORY = "OPENNI2_DRIVERS_PATH"; -#endif -static const char* ONI_DEFAULT_DRIVERS_REPOSITORY = XN_FILE_LOCAL_DIR "OpenNI2" XN_FILE_DIR_SEP "Drivers"; +static const char* ONI_CONFIGURATION_FILE = "OpenNI.ini"; +static const char* ONI_DEFAULT_DRIVERS_REPOSITORY = "OpenNI2" XN_FILE_DIR_SEP "Drivers"; ONI_NAMESPACE_IMPLEMENTATION_BEGIN @@ -44,6 +39,9 @@ Context::~Context() s_valid = FALSE; } +// Dummy function used only for taking its address for the sake of xnOSGetModulePathForProcAddress. +static void dummyFunctionToTakeAddress() {} + OniStatus Context::initialize() { XnBool repositoryOverridden = FALSE; @@ -58,6 +56,23 @@ OniStatus Context::initialize() XnStatus rc; + XnChar strModulePath[XN_FILE_MAX_PATH]; + rc = xnOSGetModulePathForProcAddress(reinterpret_cast(&dummyFunctionToTakeAddress), strModulePath); + if (rc != XN_STATUS_OK) + { + m_errorLogger.Append("Couldn't get the OpenNI shared library module's path: %s", xnGetStatusString(rc)); + return OniStatusFromXnStatus(rc); + } + + XnChar strBaseDir[XN_FILE_MAX_PATH]; + rc = xnOSGetDirName(strModulePath, strBaseDir, XN_FILE_MAX_PATH); + if (rc != XN_STATUS_OK) + { + // Very unlikely to happen, but just in case. + m_errorLogger.Append("Couldn't get the OpenNI shared library module's directory: %s", xnGetStatusString(rc)); + return OniStatusFromXnStatus(rc); + } + rc = m_newFrameAvailableEvent.Create(FALSE); if (rc != XN_STATUS_OK) { @@ -69,71 +84,85 @@ OniStatus Context::initialize() // Read configuration file + XnChar strOniConfigurationFile[XN_FILE_MAX_PATH]; XnBool configurationFileExists = FALSE; - rc = xnOSDoesFileExist(ONI_CONFIGURATION_FILE, &configurationFileExists); + + // Search the module directory for OpenNI.ini. + xnOSStrCopy(strOniConfigurationFile, strBaseDir, XN_FILE_MAX_PATH); + rc = xnOSAppendFilePath(strOniConfigurationFile, ONI_CONFIGURATION_FILE, XN_FILE_MAX_PATH); + if (rc == XN_STATUS_OK) + { + xnOSDoesFileExist(strOniConfigurationFile, &configurationFileExists); + } + if (configurationFileExists) { - rc = xnOSReadStringFromINI(ONI_CONFIGURATION_FILE, "Device", "Override", m_overrideDevice, XN_FILE_MAX_PATH); - if (rc != XN_STATUS_OK) - { - xnLogVerbose(XN_LOG_MASK_ALL, "No override device in configuration file"); - } + // First, we should process the log related configuration as early as possible. XnInt32 nValue; - rc = xnOSReadIntFromINI(ONI_CONFIGURATION_FILE, "Log", "Verbosity", &nValue); + rc = xnOSReadIntFromINI(strOniConfigurationFile, "Log", "Verbosity", &nValue); if (rc == XN_STATUS_OK) { xnLogSetMaskMinSeverity(XN_LOG_MASK_ALL, (XnLogSeverity)nValue); } - rc = xnOSReadIntFromINI(ONI_CONFIGURATION_FILE, "Log", "LogToConsole", &nValue); + rc = xnOSReadIntFromINI(strOniConfigurationFile, "Log", "LogToConsole", &nValue); if (rc == XN_STATUS_OK) { xnLogSetConsoleOutput(nValue == 1); } - rc = xnOSReadIntFromINI(ONI_CONFIGURATION_FILE, "Log", "LogToFile", &nValue); + rc = xnOSReadIntFromINI(strOniConfigurationFile, "Log", "LogToFile", &nValue); if (rc == XN_STATUS_OK) { xnLogSetFileOutput(nValue == 1); } - rc = xnOSReadStringFromINI(ONI_CONFIGURATION_FILE, "Drivers", "Repository", repositoryFromINI, XN_FILE_MAX_PATH); + + // Then, process the other device configurations. + + rc = xnOSReadStringFromINI(strOniConfigurationFile, "Device", "Override", m_overrideDevice, XN_FILE_MAX_PATH); + if (rc != XN_STATUS_OK) + { + xnLogVerbose(XN_LOG_MASK_ALL, "No override device in configuration file"); + } + + rc = xnOSReadStringFromINI(strOniConfigurationFile, "Drivers", "Repository", repositoryFromINI, XN_FILE_MAX_PATH); if (rc == XN_STATUS_OK) { repositoryOverridden = TRUE; } + + xnLogVerbose(XN_LOG_MASK_ALL, "Configuration has been read from '%s'", strOniConfigurationFile); } else { - xnLogVerbose(XN_LOG_MASK_ALL, "Couldn't find configuration file '%s'", ONI_CONFIGURATION_FILE); + xnLogVerbose(XN_LOG_MASK_ALL, "Couldn't find configuration file '%s'", strOniConfigurationFile); } xnLogVerbose(XN_LOG_MASK_ALL, "OpenNI %s", ONI_VERSION_STRING); - // Use path specified in ini file + // Resolve the drive path based on the module's directory. + XnChar strDriverPath[XN_FILE_MAX_PATH]; + xnOSStrCopy(strDriverPath, strBaseDir, XN_FILE_MAX_PATH); + if (repositoryOverridden) { - xnLogVerbose(XN_LOG_MASK_ALL, "Using '%s' as driver path, as configured in file '%s'", ONI_CONFIGURATION_FILE); - rc = loadLibraries(repositoryFromINI); - return OniStatusFromXnStatus(rc); + xnLogVerbose(XN_LOG_MASK_ALL, "Extending the driver path by '%s', as configured in file '%s'", repositoryFromINI, strOniConfigurationFile); + rc = xnOSAppendFilePath(strDriverPath, repositoryFromINI, XN_FILE_MAX_PATH); + } + else + { + rc = xnOSAppendFilePath(strDriverPath, ONI_DEFAULT_DRIVERS_REPOSITORY, XN_FILE_MAX_PATH); } - xnLogVerbose(XN_LOG_MASK_ALL, "Using '%s' as driver path", ONI_DEFAULT_DRIVERS_REPOSITORY); - // Use default path - rc = loadLibraries(ONI_DEFAULT_DRIVERS_REPOSITORY); if (rc != XN_STATUS_OK) { - // Can't find through default - try environment variable - xnLogVerbose(XN_LOG_MASK_ALL, "Can't load drivers from default directory '%s'.", ONI_DEFAULT_DRIVERS_REPOSITORY); - - char dirName[XN_FILE_MAX_PATH]; - XnStatus envrc = xnOSGetEnvironmentVariable(ONI_ENV_VAR_DRIVERS_REPOSITORY, dirName, XN_FILE_MAX_PATH); - if (envrc == XN_STATUS_OK) - { - xnLogVerbose(XN_LOG_MASK_ALL, "Using '%s' as driver path, as configured by environment variable '%s'", dirName, ONI_ENV_VAR_DRIVERS_REPOSITORY); - rc = loadLibraries(dirName); - } + m_errorLogger.Append("The driver path gets too long"); + return OniStatusFromXnStatus(rc); } + xnLogVerbose(XN_LOG_MASK_ALL, "Using '%s' as driver path", strDriverPath); + rc = loadLibraries(strDriverPath); + if (rc == XN_STATUS_OK) { m_errorLogger.Clear(); diff --git a/Source/Drivers/PS1080/Sensor/XnSensor.cpp b/Source/Drivers/PS1080/Sensor/XnSensor.cpp index 4f0362e7..b277b949 100644 --- a/Source/Drivers/PS1080/Sensor/XnSensor.cpp +++ b/Source/Drivers/PS1080/Sensor/XnSensor.cpp @@ -39,7 +39,7 @@ #define XN_SENSOR_FRAME_SYNC_MAX_DIFF 3 #define XN_SENSOR_DEFAULT_CLOSE_STREAMS_ON_SHUTDOWN TRUE #define XN_SENSOR_DEFAULT_HOST_TIMESTAMPS FALSE -#define XN_GLOBAL_CONFIG_FILE_NAME "./PS1080.ini" +#define XN_GLOBAL_CONFIG_FILE_NAME "PS1080.ini" #define FRAME_SYNC_MAX_FRAME_TIME_DIFF 3000 @@ -100,7 +100,7 @@ XnSensor::XnSensor(XnBool bResetOnStartup /* = TRUE */, XnBool bLeanInit /* = FA { // reset all data xnOSMemSet(&m_DevicePrivateData, 0, sizeof(XnDevicePrivateData)); - xnOSStrCopy(m_strGlobalConfigFile, XN_GLOBAL_CONFIG_FILE_NAME, sizeof(m_strGlobalConfigFile)); + ResolveGlobalConfigFileName(m_strGlobalConfigFile, sizeof(m_strGlobalConfigFile), NULL); m_ResetSensorOnStartup.UpdateSetCallbackToDefault(); m_LeanInit.UpdateSetCallbackToDefault(); @@ -573,8 +573,26 @@ XnStatus XnSensor::ValidateSensorID(XnChar* csSensorID) XnStatus XnSensor::ResolveGlobalConfigFileName(XnChar* strConfigFile, XnUInt32 nBufSize, const XnChar* strConfigDir) { - XnUInt32 nWritten = 0; - return xnOSStrFormat(strConfigFile, nBufSize, &nWritten, "%s%s%s", strConfigDir, XN_FILE_DIR_SEP, XN_GLOBAL_CONFIG_FILE_NAME); + // If strConfigDir is NULL, tries to resolve the config file based on the driver's directory + XnChar strBaseDir[XN_FILE_MAX_PATH]; + if (strConfigDir == NULL) + { + if (xnOSGetModulePathForProcAddress(reinterpret_cast(&XnSensor::ResolveGlobalConfigFileName), strBaseDir) == XN_STATUS_OK && + xnOSGetDirName(strBaseDir, strBaseDir, XN_FILE_MAX_PATH) == XN_STATUS_OK) + { + // Successfully obtained the driver's path + strConfigDir = strBaseDir; + } + else + { + // Something wrong happened. Use the current directory as the fallback. + strConfigDir = "."; + } + } + + XnStatus rc; + XN_VALIDATE_STR_COPY(strConfigFile, strConfigDir, nBufSize, rc); + return xnOSAppendFilePath(strConfigFile, XN_GLOBAL_CONFIG_FILE_NAME, nBufSize); } XnStatus XnSensor::SetGlobalConfigFile(const XnChar* strConfigFile) diff --git a/Source/Drivers/PS1080/Sensor/XnSensor.h b/Source/Drivers/PS1080/Sensor/XnSensor.h index 88fa43c7..996b6998 100644 --- a/Source/Drivers/PS1080/Sensor/XnSensor.h +++ b/Source/Drivers/PS1080/Sensor/XnSensor.h @@ -74,7 +74,12 @@ class XnSensor : public XnDeviceBase inline XnStatus GetErrorState() { return (XnStatus)m_ErrorState.GetValue(); } XnStatus SetErrorState(XnStatus errorState); + /** + * Resolves the config file's path. + * Specify NULL to strConfigDir to resolve it based on the driver's directory. + */ static XnStatus ResolveGlobalConfigFileName(XnChar* strConfigFile, XnUInt32 nBufSize, const XnChar* strConfigDir); + XnStatus SetGlobalConfigFile(const XnChar* strConfigFile); XnStatus ConfigureModuleFromGlobalFile(const XnChar* strModule, const XnChar* strSection = NULL); diff --git a/ThirdParty/PSCommon/XnLib/Include/Linux-x86/XnOSLinux-x86.h b/ThirdParty/PSCommon/XnLib/Include/Linux-x86/XnOSLinux-x86.h index f8d1ecd0..7a8c2459 100644 --- a/ThirdParty/PSCommon/XnLib/Include/Linux-x86/XnOSLinux-x86.h +++ b/ThirdParty/PSCommon/XnLib/Include/Linux-x86/XnOSLinux-x86.h @@ -48,6 +48,7 @@ typedef XnInt XN_FILE_HANDLE; /** The file directory separator. */ #define XN_FILE_DIR_SEP "/" +#define XN_FILE_DIR_SEPS "/" /** The file extension separator. */ #define XN_FILE_EXT_SEP "." diff --git a/ThirdParty/PSCommon/XnLib/Include/Win32/XnLibWin32.h b/ThirdParty/PSCommon/XnLib/Include/Win32/XnLibWin32.h index 6c17a941..452163ed 100644 --- a/ThirdParty/PSCommon/XnLib/Include/Win32/XnLibWin32.h +++ b/ThirdParty/PSCommon/XnLib/Include/Win32/XnLibWin32.h @@ -37,6 +37,7 @@ typedef HANDLE XN_FILE_HANDLE; /** The file directory separator. */ #define XN_FILE_DIR_SEP "\\" +#define XN_FILE_DIR_SEPS "\\/" // Win32 accepts '/' also /** The file extension separator. */ #define XN_FILE_EXT_SEP "." diff --git a/ThirdParty/PSCommon/XnLib/Include/XnOS.h b/ThirdParty/PSCommon/XnLib/Include/XnOS.h index a6e7e9f5..87ae1c66 100644 --- a/ThirdParty/PSCommon/XnLib/Include/XnOS.h +++ b/ThirdParty/PSCommon/XnLib/Include/XnOS.h @@ -463,6 +463,29 @@ XN_C_API XnStatus XN_C_DECL xnOSGetFileName(const XnChar* cpFilePath, XnChar* cp XN_C_API XnStatus XN_C_DECL xnOSGetFullPathName(const XnChar* strFilePath, XnChar* strFullPath, XnUInt32 nBufferSize); XN_C_API XnStatus XN_C_DECL xnOSGetCurrentDir(XnChar* cpDirName, const XnUInt32 nBufferSize); XN_C_API XnStatus XN_C_DECL xnOSSetCurrentDir(const XnChar* cpDirName); +/** + * Strips the directory separator at the end of the specified path by directly modifying the given string. + * Always returns XN_STATUS_OK. + */ +XN_C_API XnStatus XN_C_DECL xnOSStripDirSep(XnChar* strDirName); +/** + * Checks if the specified character works as a directory separator. + */ +XN_C_API XnBool XN_C_DECL xnOSIsDirSep(XnChar c); +/** + * Appends the specified path component(s) to the specified path buffer. + * Directory separator is applied if necessary. + * If the path component to append is an absolute path, the resulted path is completely altered with it. + * + * @param strDestPath [in] Buffer that stores the original path to be operated. + * @param strPathComponentToAppend [in] Path component(s) to append. Can be absolute or relative. + * @param nBufferSize [in] Size of strDestPath. + */ +XN_C_API XnStatus XN_C_DECL xnOSAppendFilePath(XnChar* strDestPath, const XnChar* strPathComponentToAppend, const XnUInt32 nBufferSize); +/** + * Returns true if the specified path is absolute. + */ +XN_C_API XnBool XN_C_DECL xnOSIsAbsoluteFilePath(const XnChar* strFilePath); XN_C_API XnStatus XN_C_DECL xnOSDeleteFile(const XnChar* cpFileName); XN_C_API XnStatus XN_C_DECL xnOSDeleteEmptyDirectory(const XnChar* strDirName); XN_C_API XnStatus XN_C_DECL xnOSDeleteDirectoryTree(const XnChar* strDirName); @@ -482,6 +505,14 @@ XN_C_API XnStatus XN_C_DECL xnOSLoadLibrary(const XnChar* cpFileName, XN_LIB_HAN XN_C_API XnStatus XN_C_DECL xnOSFreeLibrary(const XN_LIB_HANDLE LibHandle); XN_C_API XnStatus XN_C_DECL xnOSGetProcAddress(const XN_LIB_HANDLE LibHandle, const XnChar* cpProcName, XnFarProc* pProcAddr); +/** + * Returns the absolute path of the module that includes the specified proc address. + * + * @param procAddr [in] Proc address contained by the target module. + * @param strModulePath [in] Buffer to receive the absolute path of the module. Must have the size of XN_FILE_MAX_PATH at least. + */ +XN_C_API XnStatus XN_C_DECL xnOSGetModulePathForProcAddress(void* procAddr, XnChar *strModulePath); + struct timespec; // Time diff --git a/ThirdParty/PSCommon/XnLib/Source/Linux/XnLinuxFiles.cpp b/ThirdParty/PSCommon/XnLib/Source/Linux/XnLinuxFiles.cpp index 72a01332..bc986f3f 100644 --- a/ThirdParty/PSCommon/XnLib/Source/Linux/XnLinuxFiles.cpp +++ b/ThirdParty/PSCommon/XnLib/Source/Linux/XnLinuxFiles.cpp @@ -681,3 +681,7 @@ XN_C_API XnStatus xnOSDoesDirectoryExist(const XnChar* cpDirName, XnBool* pbResu return (XN_STATUS_OK); } +XN_C_API XnBool xnOSIsAbsoluteFilePath(const XnChar* strFilePath) +{ + return xnOSIsDirSep(strFilePath[0]); +} diff --git a/ThirdParty/PSCommon/XnLib/Source/Linux/XnLinuxSharedLibs.cpp b/ThirdParty/PSCommon/XnLib/Source/Linux/XnLinuxSharedLibs.cpp index 9d34886e..f6c653d5 100644 --- a/ThirdParty/PSCommon/XnLib/Source/Linux/XnLinuxSharedLibs.cpp +++ b/ThirdParty/PSCommon/XnLib/Source/Linux/XnLinuxSharedLibs.cpp @@ -34,8 +34,20 @@ XN_C_API XnStatus xnOSLoadLibrary(const XnChar* cpFileName, XN_LIB_HANDLE* pLibH XN_VALIDATE_INPUT_PTR(cpFileName); XN_VALIDATE_OUTPUT_PTR(pLibHandle); + // Resolve the file name to the absolute path. This is necessary because + // we need to get the absolute path of this library by dladdr() later. + // Note dladdr() seems to return the path specified to dlopen() "as it is". + XnChar* strAbsoluteFileName = realpath(cpFileName, NULL); + if (strAbsoluteFileName == NULL) + { + // error + xnLogWarning(XN_MASK_OS, "Failed to get absolute path for lib: %s\n", cpFileName); + return XN_STATUS_OS_CANT_LOAD_LIB; + } + // Load the requested shared library via the OS - *pLibHandle = dlopen(cpFileName, RTLD_NOW); + *pLibHandle = dlopen(strAbsoluteFileName, RTLD_NOW); + free(strAbsoluteFileName); // Don't forget to free the memory allocated by realpath(). // Make sure it succeeded (return value is not NULL). If not return an error.... if (*pLibHandle == NULL) @@ -81,3 +93,15 @@ XN_C_API XnStatus xnOSGetProcAddress(const XN_LIB_HANDLE LibHandle, const XnChar // All is good... return (XN_STATUS_OK); } + +XN_C_API XnStatus xnOSGetModulePathForProcAddress(void* procAddr, XnChar *strModulePath) +{ + Dl_info info; + if (!dladdr(procAddr, &info)) + { + xnLogWarning(XN_MASK_OS, "Failed to get the dl info: %s\n", dlerror()); + return XN_STATUS_ERROR; + } + + return xnOSStrCopy(strModulePath, info.dli_fname, XN_FILE_MAX_PATH); +} diff --git a/ThirdParty/PSCommon/XnLib/Source/Win32/XnWin32Files.cpp b/ThirdParty/PSCommon/XnLib/Source/Win32/XnWin32Files.cpp index 2cda2be0..ceafcd6b 100644 --- a/ThirdParty/PSCommon/XnLib/Source/Win32/XnWin32Files.cpp +++ b/ThirdParty/PSCommon/XnLib/Source/Win32/XnWin32Files.cpp @@ -704,6 +704,7 @@ XN_C_API XnStatus xnOSGetDirName(const XnChar* cpFilePath, XnChar* cpDirName, co } pFileName[0] = '\0'; + xnOSStripDirSep(strFullPath); strcpy(cpDirName, strFullPath); return XN_STATUS_OK; @@ -746,3 +747,9 @@ XN_C_API XnStatus xnOSGetFullPathName(const XnChar* strFilePath, XnChar* strFull return XN_STATUS_OK; } + +XN_C_API XnBool xnOSIsAbsoluteFilePath(const XnChar* strFilePath) +{ + // If the path starts with , it is absolute. + return xnOSStrLen(strFilePath) >= 3 && isalpha(strFilePath[0]) && strFilePath[1] == ':' && xnOSIsDirSep(strFilePath[2]); +} diff --git a/ThirdParty/PSCommon/XnLib/Source/Win32/XnWin32SharedLibrary.cpp b/ThirdParty/PSCommon/XnLib/Source/Win32/XnWin32SharedLibrary.cpp index 9b327455..5fb64e2a 100644 --- a/ThirdParty/PSCommon/XnLib/Source/Win32/XnWin32SharedLibrary.cpp +++ b/ThirdParty/PSCommon/XnLib/Source/Win32/XnWin32SharedLibrary.cpp @@ -82,3 +82,21 @@ XN_C_API XnStatus xnOSGetProcAddress(const XN_LIB_HANDLE LibHandle, const XnChar // All is good... return (XN_STATUS_OK); } + +XN_C_API XnStatus xnOSGetModulePathForProcAddress(void* procAddr, XnChar *strModulePath) +{ + HMODULE hModule; + BOOL rc = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)procAddr, &hModule); + if (!rc) + { + return XN_STATUS_ERROR; + } + + DWORD len = GetModuleFileName(hModule, strModulePath, XN_FILE_MAX_PATH); + if (len == 0) + { + return XN_STATUS_ERROR; + } + + return XN_STATUS_OK; +} diff --git a/ThirdParty/PSCommon/XnLib/Source/XnFiles.cpp b/ThirdParty/PSCommon/XnLib/Source/XnFiles.cpp index 684f61dc..1df52784 100644 --- a/ThirdParty/PSCommon/XnLib/Source/XnFiles.cpp +++ b/ThirdParty/PSCommon/XnLib/Source/XnFiles.cpp @@ -106,3 +106,36 @@ XN_C_API XnStatus xnOSAppendFile(const XnChar* cpFileName, const void* pBuffer, // All is good... return (XN_STATUS_OK); } + +XN_C_API XnStatus xnOSStripDirSep(XnChar* strDirName) +{ + XnUInt32 len = xnOSStrLen(strDirName); + if (len > 0 && xnOSIsDirSep(strDirName[len-1])) + { + strDirName[len-1] = '\0'; + } + return XN_STATUS_OK; +} + +XN_C_API XnBool xnOSIsDirSep(XnChar c) +{ + return (c != '\0') && (strchr(XN_FILE_DIR_SEPS, c) != NULL); +} + +XN_C_API XnStatus XN_C_DECL xnOSAppendFilePath(XnChar* strDestPath, const XnChar* strPathComponentToAppend, const XnUInt32 nBufferSize) +{ + XnStatus rc; + if (xnOSIsAbsoluteFilePath(strPathComponentToAppend)) + { + // If the path to append is absolute, use it entirely. + XN_VALIDATE_STR_COPY(strDestPath, strPathComponentToAppend, nBufferSize, rc); + } + else + { + // If the path to append is relative, append it after applyling the separator as needed. + xnOSStripDirSep(strDestPath); + XN_VALIDATE_STR_APPEND(strDestPath, XN_FILE_DIR_SEP, nBufferSize, rc); + XN_VALIDATE_STR_APPEND(strDestPath, strPathComponentToAppend, nBufferSize, rc); + } + return XN_STATUS_OK; +}