summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/path/path.c
diff options
context:
space:
mode:
Diffstat (limited to 'winpr/libwinpr/path/path.c')
-rw-r--r--winpr/libwinpr/path/path.c1181
1 files changed, 1181 insertions, 0 deletions
diff --git a/winpr/libwinpr/path/path.c b/winpr/libwinpr/path/path.c
new file mode 100644
index 0000000..82e6be1
--- /dev/null
+++ b/winpr/libwinpr/path/path.c
@@ -0,0 +1,1181 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Path Functions
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+
+#include <winpr/path.h>
+#include <winpr/file.h>
+
+#define PATH_SLASH_CHR '/'
+#define PATH_SLASH_STR "/"
+
+#define PATH_BACKSLASH_CHR '\\'
+#define PATH_BACKSLASH_STR "\\"
+
+#ifdef _WIN32
+#define PATH_SLASH_STR_W L"/"
+#define PATH_BACKSLASH_STR_W L"\\"
+#else
+#define PATH_SLASH_STR_W \
+ { \
+ '/', '\0' \
+ }
+#define PATH_BACKSLASH_STR_W \
+ { \
+ '\\', '\0' \
+ }
+#endif
+
+#ifdef _WIN32
+#define PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define PATH_SEPARATOR_STR PATH_BACKSLASH_STR
+#define PATH_SEPARATOR_STR_W PATH_BACKSLASH_STR_W
+#else
+#define PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define PATH_SEPARATOR_STR PATH_SLASH_STR
+#define PATH_SEPARATOR_STR_W PATH_SLASH_STR_W
+#endif
+
+#define SHARED_LIBRARY_EXT_DLL "dll"
+#define SHARED_LIBRARY_EXT_SO "so"
+#define SHARED_LIBRARY_EXT_DYLIB "dylib"
+
+#ifdef _WIN32
+#define SHARED_LIBRARY_EXT SHARED_LIBRARY_EXT_DLL
+#elif defined(__APPLE__)
+#define SHARED_LIBRARY_EXT SHARED_LIBRARY_EXT_DYLIB
+#else
+#define SHARED_LIBRARY_EXT SHARED_LIBRARY_EXT_SO
+#endif
+
+#include "../log.h"
+#define TAG WINPR_TAG("path")
+
+/*
+ * PathCchAddBackslash
+ */
+
+/* Windows-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define PATH_CCH_ADD_SEPARATOR PathCchAddBackslashA
+#include "include/PathCchAddSeparator.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define PATH_CCH_ADD_SEPARATOR PathCchAddBackslashW
+#include "include/PathCchAddSeparator.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR
+
+/* Unix-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define PATH_CCH_ADD_SEPARATOR PathCchAddSlashA
+#include "include/PathCchAddSeparator.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define PATH_CCH_ADD_SEPARATOR PathCchAddSlashW
+#include "include/PathCchAddSeparator.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR
+
+/* Native-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
+#define PATH_CCH_ADD_SEPARATOR PathCchAddSeparatorA
+#include "include/PathCchAddSeparator.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
+#define PATH_CCH_ADD_SEPARATOR PathCchAddSeparatorW
+#include "include/PathCchAddSeparator.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR
+
+/*
+ * PathCchRemoveBackslash
+ */
+
+HRESULT PathCchRemoveBackslashA(PSTR pszPath, size_t cchPath)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchRemoveBackslashW(PWSTR pszPath, size_t cchPath)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/*
+ * PathCchAddBackslashEx
+ */
+
+/* Windows-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddBackslashExA
+#include "include/PathCchAddSeparatorEx.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR_EX
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddBackslashExW
+#include "include/PathCchAddSeparatorEx.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR_EX
+
+/* Unix-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSlashExA
+#include "include/PathCchAddSeparatorEx.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR_EX
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSlashExW
+#include "include/PathCchAddSeparatorEx.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR_EX
+
+/* Native-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
+#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSeparatorExA
+#include "include/PathCchAddSeparatorEx.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR_EX
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
+#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSeparatorExW
+#include "include/PathCchAddSeparatorEx.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_SEPARATOR_EX
+
+HRESULT PathCchRemoveBackslashExA(PSTR pszPath, size_t cchPath, PSTR* ppszEnd,
+ size_t* pcchRemaining)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchRemoveBackslashExW(PWSTR pszPath, size_t cchPath, PWSTR* ppszEnd,
+ size_t* pcchRemaining)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/*
+ * PathCchAddExtension
+ */
+
+/* Windows-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define PATH_CCH_ADD_EXTENSION PathCchAddExtensionA
+#include "include/PathCchAddExtension.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_EXTENSION
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define PATH_CCH_ADD_EXTENSION PathCchAddExtensionW
+#include "include/PathCchAddExtension.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_EXTENSION
+
+/* Unix-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define PATH_CCH_ADD_EXTENSION UnixPathCchAddExtensionA
+#include "include/PathCchAddExtension.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_EXTENSION
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define PATH_CCH_ADD_EXTENSION UnixPathCchAddExtensionW
+#include "include/PathCchAddExtension.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_EXTENSION
+
+/* Native-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
+#define PATH_CCH_ADD_EXTENSION NativePathCchAddExtensionA
+#include "include/PathCchAddExtension.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_EXTENSION
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
+#define PATH_CCH_ADD_EXTENSION NativePathCchAddExtensionW
+#include "include/PathCchAddExtension.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef PATH_CCH_ADD_EXTENSION
+
+/*
+ * PathCchAppend
+ */
+
+/* Windows-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR
+#define PATH_CCH_APPEND PathCchAppendA
+#include "include/PathCchAppend.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_CCH_APPEND
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR_W
+#define PATH_CCH_APPEND PathCchAppendW
+#include "include/PathCchAppend.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_CCH_APPEND
+
+/* Unix-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR
+#define PATH_CCH_APPEND UnixPathCchAppendA
+#include "include/PathCchAppend.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_CCH_APPEND
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR_W
+#define PATH_CCH_APPEND UnixPathCchAppendW
+#include "include/PathCchAppend.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_CCH_APPEND
+
+/* Native-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR
+#define PATH_CCH_APPEND NativePathCchAppendA
+#include "include/PathCchAppend.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_CCH_APPEND
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR_W
+#define PATH_CCH_APPEND NativePathCchAppendW
+#include "include/PathCchAppend.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_CCH_APPEND
+
+/*
+ * PathCchAppendEx
+ */
+
+HRESULT PathCchAppendExA(PSTR pszPath, size_t cchPath, PCSTR pszMore, unsigned long dwFlags)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchAppendExW(PWSTR pszPath, size_t cchPath, PCWSTR pszMore, unsigned long dwFlags)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/*
+ * PathCchCanonicalize
+ */
+
+HRESULT PathCchCanonicalizeA(PSTR pszPathOut, size_t cchPathOut, PCSTR pszPathIn)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchCanonicalizeW(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/*
+ * PathCchCanonicalizeEx
+ */
+
+HRESULT PathCchCanonicalizeExA(PSTR pszPathOut, size_t cchPathOut, PCSTR pszPathIn,
+ unsigned long dwFlags)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchCanonicalizeExW(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn,
+ unsigned long dwFlags)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/*
+ * PathAllocCanonicalize
+ */
+
+HRESULT PathAllocCanonicalizeA(PCSTR pszPathIn, unsigned long dwFlags, PSTR* ppszPathOut)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathAllocCanonicalizeW(PCWSTR pszPathIn, unsigned long dwFlags, PWSTR* ppszPathOut)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/*
+ * PathCchCombine
+ */
+
+HRESULT PathCchCombineA(PSTR pszPathOut, size_t cchPathOut, PCSTR pszPathIn, PCSTR pszMore)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchCombineW(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn, PCWSTR pszMore)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/*
+ * PathCchCombineEx
+ */
+
+HRESULT PathCchCombineExA(PSTR pszPathOut, size_t cchPathOut, PCSTR pszPathIn, PCSTR pszMore,
+ unsigned long dwFlags)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchCombineExW(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn, PCWSTR pszMore,
+ unsigned long dwFlags)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/*
+ * PathAllocCombine
+ */
+
+/* Windows-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR
+#define PATH_ALLOC_COMBINE PathAllocCombineA
+#include "include/PathAllocCombine.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_ALLOC_COMBINE
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR_W
+#define PATH_ALLOC_COMBINE PathAllocCombineW
+#include "include/PathAllocCombine.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_ALLOC_COMBINE
+
+/* Unix-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR
+#define PATH_ALLOC_COMBINE UnixPathAllocCombineA
+#include "include/PathAllocCombine.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_ALLOC_COMBINE
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR_W
+#define PATH_ALLOC_COMBINE UnixPathAllocCombineW
+#include "include/PathAllocCombine.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_ALLOC_COMBINE
+
+/* Native-style Paths */
+
+#define DEFINE_UNICODE FALSE
+#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR
+#define PATH_ALLOC_COMBINE NativePathAllocCombineA
+#include "include/PathAllocCombine.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_ALLOC_COMBINE
+
+#define DEFINE_UNICODE TRUE
+#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
+#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR_W
+#define PATH_ALLOC_COMBINE NativePathAllocCombineW
+#include "include/PathAllocCombine.c"
+#undef DEFINE_UNICODE
+#undef CUR_PATH_SEPARATOR_CHR
+#undef CUR_PATH_SEPARATOR_STR
+#undef PATH_ALLOC_COMBINE
+
+/**
+ * PathCchFindExtension
+ */
+
+HRESULT PathCchFindExtensionA(PCSTR pszPath, size_t cchPath, PCSTR* ppszExt)
+{
+ const char* p = (const char*)pszPath;
+
+ if (!pszPath || !cchPath || !ppszExt)
+ return E_INVALIDARG;
+
+ /* find end of string */
+
+ while (*p && --cchPath)
+ {
+ p++;
+ }
+
+ if (*p)
+ {
+ /* pszPath is not null terminated within the cchPath range */
+ return E_INVALIDARG;
+ }
+
+ /* If no extension is found, ppszExt must point to the string's terminating null */
+ *ppszExt = p;
+
+ /* search backwards for '.' */
+
+ while (p > pszPath)
+ {
+ if (*p == '.')
+ {
+ *ppszExt = (PCSTR)p;
+ break;
+ }
+
+ if ((*p == '\\') || (*p == '/') || (*p == ':'))
+ break;
+
+ p--;
+ }
+
+ return S_OK;
+}
+
+HRESULT PathCchFindExtensionW(PCWSTR pszPath, size_t cchPath, PCWSTR* ppszExt)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/**
+ * PathCchRenameExtension
+ */
+
+HRESULT PathCchRenameExtensionA(PSTR pszPath, size_t cchPath, PCSTR pszExt)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchRenameExtensionW(PWSTR pszPath, size_t cchPath, PCWSTR pszExt)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/**
+ * PathCchRemoveExtension
+ */
+
+HRESULT PathCchRemoveExtensionA(PSTR pszPath, size_t cchPath)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchRemoveExtensionW(PWSTR pszPath, size_t cchPath)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/**
+ * PathCchIsRoot
+ */
+
+BOOL PathCchIsRootA(PCSTR pszPath)
+{
+ WLog_ERR(TAG, "not implemented");
+ return FALSE;
+}
+
+BOOL PathCchIsRootW(PCWSTR pszPath)
+{
+ WLog_ERR(TAG, "not implemented");
+ return FALSE;
+}
+
+/**
+ * PathIsUNCEx
+ */
+
+BOOL PathIsUNCExA(PCSTR pszPath, PCSTR* ppszServer)
+{
+ if (!pszPath)
+ return FALSE;
+
+ if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
+ {
+ *ppszServer = &pszPath[2];
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL PathIsUNCExW(PCWSTR pszPath, PCWSTR* ppszServer)
+{
+ if (!pszPath)
+ return FALSE;
+
+ if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
+ {
+ *ppszServer = &pszPath[2];
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * PathCchSkipRoot
+ */
+
+HRESULT PathCchSkipRootA(PCSTR pszPath, PCSTR* ppszRootEnd)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchSkipRootW(PCWSTR pszPath, PCWSTR* ppszRootEnd)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/**
+ * PathCchStripToRoot
+ */
+
+HRESULT PathCchStripToRootA(PSTR pszPath, size_t cchPath)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchStripToRootW(PWSTR pszPath, size_t cchPath)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/**
+ * PathCchStripPrefix
+ */
+
+HRESULT PathCchStripPrefixA(PSTR pszPath, size_t cchPath)
+{
+ BOOL hasPrefix = 0;
+
+ if (!pszPath)
+ return E_INVALIDARG;
+
+ if (cchPath < 4 || cchPath > PATHCCH_MAX_CCH)
+ return E_INVALIDARG;
+
+ hasPrefix = ((pszPath[0] == '\\') && (pszPath[1] == '\\') && (pszPath[2] == '?') &&
+ (pszPath[3] == '\\'))
+ ? TRUE
+ : FALSE;
+
+ if (hasPrefix)
+ {
+ if (cchPath < 6)
+ return S_FALSE;
+
+ if (IsCharAlpha(pszPath[4]) && (pszPath[5] == ':')) /* like C: */
+ {
+ memmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4);
+ /* since the passed pszPath must not necessarily be null terminated
+ * and we always have enough space after the strip we can always
+ * ensure the null termination of the stripped result
+ */
+ pszPath[cchPath - 4] = 0;
+ return S_OK;
+ }
+ }
+
+ return S_FALSE;
+}
+
+HRESULT PathCchStripPrefixW(PWSTR pszPath, size_t cchPath)
+{
+ BOOL hasPrefix = 0;
+
+ if (!pszPath)
+ return E_INVALIDARG;
+
+ if (cchPath < 4 || cchPath > PATHCCH_MAX_CCH)
+ return E_INVALIDARG;
+
+ hasPrefix = ((pszPath[0] == '\\') && (pszPath[1] == '\\') && (pszPath[2] == '?') &&
+ (pszPath[3] == '\\'))
+ ? TRUE
+ : FALSE;
+
+ if (hasPrefix)
+ {
+ int rc = 0;
+ if (cchPath < 6)
+ return S_FALSE;
+
+ rc = (_wcslen(&pszPath[4]) + 1);
+ if ((rc < 0) || ((INT64)cchPath < rc))
+ return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+
+ if (IsCharAlphaW(pszPath[4]) && (pszPath[5] == L':')) /* like C: */
+ {
+ wmemmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4);
+ /* since the passed pszPath must not necessarily be null terminated
+ * and we always have enough space after the strip we can always
+ * ensure the null termination of the stripped result
+ */
+ pszPath[cchPath - 4] = 0;
+ return S_OK;
+ }
+ }
+
+ return S_FALSE;
+}
+
+/**
+ * PathCchRemoveFileSpec
+ */
+
+HRESULT PathCchRemoveFileSpecA(PSTR pszPath, size_t cchPath)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+HRESULT PathCchRemoveFileSpecW(PWSTR pszPath, size_t cchPath)
+{
+ WLog_ERR(TAG, "not implemented");
+ return E_NOTIMPL;
+}
+
+/*
+ * Path Portability Functions
+ */
+
+/**
+ * PathCchConvertStyle
+ */
+
+HRESULT PathCchConvertStyleA(PSTR pszPath, size_t cchPath, unsigned long dwFlags)
+{
+ if (dwFlags == PATH_STYLE_WINDOWS)
+ {
+ for (size_t index = 0; index < cchPath; index++)
+ {
+ if (pszPath[index] == PATH_SLASH_CHR)
+ pszPath[index] = PATH_BACKSLASH_CHR;
+ }
+ }
+ else if (dwFlags == PATH_STYLE_UNIX)
+ {
+ for (size_t index = 0; index < cchPath; index++)
+ {
+ if (pszPath[index] == PATH_BACKSLASH_CHR)
+ pszPath[index] = PATH_SLASH_CHR;
+ }
+ }
+ else if (dwFlags == PATH_STYLE_NATIVE)
+ {
+#if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR)
+ /* Unix-style to Windows-style */
+
+ for (size_t index = 0; index < cchPath; index++)
+ {
+ if (pszPath[index] == PATH_SLASH_CHR)
+ pszPath[index] = PATH_BACKSLASH_CHR;
+ }
+#elif (PATH_SEPARATOR_CHR == PATH_SLASH_CHR)
+ /* Windows-style to Unix-style */
+
+ for (size_t index = 0; index < cchPath; index++)
+ {
+ if (pszPath[index] == PATH_BACKSLASH_CHR)
+ pszPath[index] = PATH_SLASH_CHR;
+ }
+#else
+ /* Unexpected error */
+ return E_FAIL;
+#endif
+ }
+ else
+ {
+ /* Gangnam style? */
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+HRESULT PathCchConvertStyleW(PWSTR pszPath, size_t cchPath, unsigned long dwFlags)
+{
+ if (dwFlags == PATH_STYLE_WINDOWS)
+ {
+ for (size_t index = 0; index < cchPath; index++)
+ {
+ if (pszPath[index] == PATH_SLASH_CHR)
+ pszPath[index] = PATH_BACKSLASH_CHR;
+ }
+ }
+ else if (dwFlags == PATH_STYLE_UNIX)
+ {
+ for (size_t index = 0; index < cchPath; index++)
+ {
+ if (pszPath[index] == PATH_BACKSLASH_CHR)
+ pszPath[index] = PATH_SLASH_CHR;
+ }
+ }
+ else if (dwFlags == PATH_STYLE_NATIVE)
+ {
+#if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR)
+ {
+ /* Unix-style to Windows-style */
+
+ for (size_t index = 0; index < cchPath; index++)
+ {
+ if (pszPath[index] == PATH_SLASH_CHR)
+ pszPath[index] = PATH_BACKSLASH_CHR;
+ }
+ }
+#elif (PATH_SEPARATOR_CHR == PATH_SLASH_CHR)
+ {
+ /* Windows-style to Unix-style */
+
+ for (size_t index = 0; index < cchPath; index++)
+ {
+ if (pszPath[index] == PATH_BACKSLASH_CHR)
+ pszPath[index] = PATH_SLASH_CHR;
+ }
+ }
+#else
+ {
+ /* Unexpected error */
+ return E_FAIL;
+ }
+#endif
+ }
+ else
+ {
+ /* Gangnam style? */
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+/**
+ * PathGetSeparator
+ */
+
+char PathGetSeparatorA(unsigned long dwFlags)
+{
+ char separator = PATH_SEPARATOR_CHR;
+
+ if (!dwFlags)
+ dwFlags = PATH_STYLE_NATIVE;
+
+ if (dwFlags == PATH_STYLE_WINDOWS)
+ separator = PATH_SEPARATOR_CHR;
+ else if (dwFlags == PATH_STYLE_UNIX)
+ separator = PATH_SEPARATOR_CHR;
+ else if (dwFlags == PATH_STYLE_NATIVE)
+ separator = PATH_SEPARATOR_CHR;
+
+ return separator;
+}
+
+WCHAR PathGetSeparatorW(unsigned long dwFlags)
+{
+ union
+ {
+ WCHAR w;
+ char c[2];
+ } cnv;
+
+ cnv.c[0] = PATH_SEPARATOR_CHR;
+ cnv.c[1] = '\0';
+
+ if (!dwFlags)
+ dwFlags = PATH_STYLE_NATIVE;
+
+ if (dwFlags == PATH_STYLE_WINDOWS)
+ cnv.c[0] = PATH_SEPARATOR_CHR;
+ else if (dwFlags == PATH_STYLE_UNIX)
+ cnv.c[0] = PATH_SEPARATOR_CHR;
+ else if (dwFlags == PATH_STYLE_NATIVE)
+ cnv.c[0] = PATH_SEPARATOR_CHR;
+
+ return cnv.w;
+}
+
+/**
+ * PathGetSharedLibraryExtension
+ */
+static const CHAR SharedLibraryExtensionDllA[] = "dll";
+static const CHAR SharedLibraryExtensionSoA[] = "so";
+static const CHAR SharedLibraryExtensionDylibA[] = "dylib";
+
+static const CHAR SharedLibraryExtensionDotDllA[] = ".dll";
+static const CHAR SharedLibraryExtensionDotSoA[] = ".so";
+static const CHAR SharedLibraryExtensionDotDylibA[] = ".dylib";
+PCSTR PathGetSharedLibraryExtensionA(unsigned long dwFlags)
+{
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
+ {
+ if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
+ {
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
+ return SharedLibraryExtensionDotDllA;
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
+ return SharedLibraryExtensionDotSoA;
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
+ return SharedLibraryExtensionDotDylibA;
+ }
+ else
+ {
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
+ return SharedLibraryExtensionDllA;
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
+ return SharedLibraryExtensionSoA;
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
+ return SharedLibraryExtensionDylibA;
+ }
+ }
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
+ {
+#ifdef _WIN32
+ return SharedLibraryExtensionDotDllA;
+#elif defined(__APPLE__)
+ if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
+ return SharedLibraryExtensionDotSoA;
+ else
+ return SharedLibraryExtensionDotDylibA;
+#else
+ return SharedLibraryExtensionDotSoA;
+#endif
+ }
+ else
+ {
+#ifdef _WIN32
+ return SharedLibraryExtensionDllA;
+#elif defined(__APPLE__)
+ if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
+ return SharedLibraryExtensionSoA;
+ else
+ return SharedLibraryExtensionDylibA;
+#else
+ return SharedLibraryExtensionSoA;
+#endif
+ }
+
+ return NULL;
+}
+
+PCWSTR PathGetSharedLibraryExtensionW(unsigned long dwFlags)
+{
+ WCHAR buffer[6][16] = { 0 };
+ const WCHAR* SharedLibraryExtensionDotDllW = InitializeConstWCharFromUtf8(
+ SharedLibraryExtensionDotDllA, buffer[0], ARRAYSIZE(buffer[0]));
+ const WCHAR* SharedLibraryExtensionDotSoW =
+ InitializeConstWCharFromUtf8(SharedLibraryExtensionDotSoA, buffer[1], ARRAYSIZE(buffer[1]));
+ const WCHAR* SharedLibraryExtensionDotDylibW = InitializeConstWCharFromUtf8(
+ SharedLibraryExtensionDotDylibA, buffer[2], ARRAYSIZE(buffer[2]));
+ const WCHAR* SharedLibraryExtensionDllW =
+ InitializeConstWCharFromUtf8(SharedLibraryExtensionDllA, buffer[3], ARRAYSIZE(buffer[3]));
+ const WCHAR* SharedLibraryExtensionSoW =
+ InitializeConstWCharFromUtf8(SharedLibraryExtensionSoA, buffer[4], ARRAYSIZE(buffer[4]));
+ const WCHAR* SharedLibraryExtensionDylibW =
+ InitializeConstWCharFromUtf8(SharedLibraryExtensionDylibA, buffer[5], ARRAYSIZE(buffer[5]));
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
+ {
+ if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
+ {
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
+ return SharedLibraryExtensionDotDllW;
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
+ return SharedLibraryExtensionDotSoW;
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
+ return SharedLibraryExtensionDotDylibW;
+ }
+ else
+ {
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
+ return SharedLibraryExtensionDllW;
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
+ return SharedLibraryExtensionSoW;
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
+ return SharedLibraryExtensionDylibW;
+ }
+ }
+
+ if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
+ {
+#ifdef _WIN32
+ return SharedLibraryExtensionDotDllW;
+#elif defined(__APPLE__)
+ if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
+ return SharedLibraryExtensionDotSoW;
+ else
+ return SharedLibraryExtensionDotDylibW;
+#else
+ return SharedLibraryExtensionDotSoW;
+#endif
+ }
+ else
+ {
+#ifdef _WIN32
+ return SharedLibraryExtensionDllW;
+#elif defined(__APPLE__)
+ if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
+ return SharedLibraryExtensionSoW;
+ else
+ return SharedLibraryExtensionDylibW;
+#else
+ return SharedLibraryExtensionSoW;
+#endif
+ }
+
+ return NULL;
+}
+
+const char* GetKnownPathIdString(int id)
+{
+ switch (id)
+ {
+ case KNOWN_PATH_HOME:
+ return "KNOWN_PATH_HOME";
+ case KNOWN_PATH_TEMP:
+ return "KNOWN_PATH_TEMP";
+ case KNOWN_PATH_XDG_DATA_HOME:
+ return "KNOWN_PATH_XDG_DATA_HOME";
+ case KNOWN_PATH_XDG_CONFIG_HOME:
+ return "KNOWN_PATH_XDG_CONFIG_HOME";
+ case KNOWN_PATH_XDG_CACHE_HOME:
+ return "KNOWN_PATH_XDG_CACHE_HOME";
+ case KNOWN_PATH_XDG_RUNTIME_DIR:
+ return "KNOWN_PATH_XDG_RUNTIME_DIR";
+ default:
+ return "KNOWN_PATH_UNKNOWN_ID";
+ }
+}
+
+static WCHAR* concat(const WCHAR* path, size_t pathlen, const WCHAR* name, size_t namelen)
+{
+ WCHAR* str = calloc(pathlen + namelen + 1, sizeof(WCHAR));
+ if (!str)
+ return NULL;
+
+ _wcsncat(str, path, pathlen);
+ _wcsncat(str, name, namelen);
+ return str;
+}
+
+BOOL winpr_RemoveDirectory_RecursiveA(LPCSTR lpPathName)
+{
+ WCHAR* name = ConvertUtf8ToWCharAlloc(lpPathName, NULL);
+ if (!name)
+ return FALSE;
+ const BOOL rc = winpr_RemoveDirectory_RecursiveW(name);
+ free(name);
+ return rc;
+}
+
+BOOL winpr_RemoveDirectory_RecursiveW(LPCWSTR lpPathName)
+{
+ BOOL ret = FALSE;
+
+ if (!lpPathName)
+ return FALSE;
+
+ const size_t pathnamelen = _wcslen(lpPathName);
+ const size_t path_slash_len = pathnamelen + 3;
+ WCHAR* path_slash = calloc(pathnamelen + 4, sizeof(WCHAR));
+ if (!path_slash)
+ return FALSE;
+ _wcsncat(path_slash, lpPathName, pathnamelen);
+
+ WCHAR starbuffer[8] = { 0 };
+ const WCHAR* star = InitializeConstWCharFromUtf8("*", starbuffer, ARRAYSIZE(starbuffer));
+ const HRESULT hr = NativePathCchAppendW(path_slash, path_slash_len, star);
+ if (FAILED(hr))
+ goto fail;
+
+ WIN32_FIND_DATAW findFileData = { 0 };
+ HANDLE dir = FindFirstFileW(path_slash, &findFileData);
+
+ if (dir == INVALID_HANDLE_VALUE)
+ goto fail;
+
+ ret = TRUE;
+ path_slash[path_slash_len - 1] = '\0'; /* remove trailing '*' */
+ do
+ {
+ const size_t len = _wcsnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName));
+
+ if ((len == 1 && findFileData.cFileName[0] == '.') ||
+ (len == 2 && findFileData.cFileName[0] == '.' && findFileData.cFileName[1] == '.'))
+ {
+ continue;
+ }
+
+ WCHAR* fullpath = concat(path_slash, path_slash_len, findFileData.cFileName, len);
+ if (!fullpath)
+ goto fail;
+
+ if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ ret = winpr_RemoveDirectory_RecursiveW(fullpath);
+ else
+ ret = DeleteFileW(fullpath);
+
+ free(fullpath);
+
+ if (!ret)
+ break;
+ } while (ret && FindNextFileW(dir, &findFileData) != 0);
+
+ FindClose(dir);
+
+ if (ret)
+ {
+ if (!RemoveDirectoryW(lpPathName))
+ ret = FALSE;
+ }
+
+fail:
+ free(path_slash);
+ return ret;
+}