WindowsPath.h#
Fully qualified name: carb/extras/WindowsPath.h
File members: carb/extras/WindowsPath.h
// SPDX-FileCopyrightText: Copyright (c) 2018-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: LicenseRef-NvidiaProprietary
//
// NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
// property and proprietary rights in and to this material, related
// documentation and any modifications thereto. Any use, reproduction,
// disclosure or distribution of this material and related documentation
// without an express license agreement from NVIDIA CORPORATION or
// its affiliates is strictly prohibited.
#pragma once
#include "../Defines.h"
#if CARB_PLATFORM_WINDOWS || defined(DOXYGEN_BUILD)
# include "../CarbWindows.h"
# include "../Error.h"
# include "../../omni/Expected.h"
# include "Unicode.h"
# include <algorithm>
# include <string>
namespace carb::extras
{
constexpr cpp::wzstring_view kLongPathPrefix(LR"(\\?\)");
namespace detail
{
template <class StringType>
StringType convertWindowsToCarbonitePath(cpp::wstring_view pathW)
{
if (pathW.starts_with(kLongPathPrefix))
pathW.remove_prefix(kLongPathPrefix.size());
auto path = convertWideStringToUtf8<StringType>(pathW);
std::replace(path.begin(), path.end(), '\\', '/');
return path;
}
} // namespace detail
std::wstring convertCarboniteToWindowsPath(cpp::string_view path);
std::wstring convertCarboniteToWindowsPath(cpp::unbounded_string path);
std::string convertWindowsToCarbonitePath(cpp::wstring_view pathW);
std::string convertWindowsToCarbonitePath(cpp::unbounded_wstring path);
std::wstring fixWindowsPathPrefix(std::wstring pathW);
std::wstring getWindowsCanonicalPath(const std::wstring& pathW);
std::wstring getWindowsFullPath(const std::wstring& pathW);
void adjustWindowsDllSearchPaths();
//
// Implementations
//
inline std::wstring convertCarboniteToWindowsPath(cpp::string_view path)
{
auto pathW = convertUtf8StringToWide<std::wstring>(path);
std::replace(pathW.begin(), pathW.end(), L'/', L'\\');
const bool hasPrefix = pathW.compare(0, kLongPathPrefix.size(), kLongPathPrefix) == 0;
if (!hasPrefix && pathW.size() >= CARBWIN_MAX_PATH)
return extras::join(kLongPathPrefix, pathW);
if (hasPrefix && pathW.size() < CARBWIN_MAX_PATH)
pathW.erase(0, kLongPathPrefix.size());
return pathW;
}
inline std::wstring convertCarboniteToWindowsPath(cpp::unbounded_string path)
{
return convertCarboniteToWindowsPath(cpp::string_view(cpp::unsafe_length, path));
}
inline std::string convertWindowsToCarbonitePath(cpp::wstring_view pathW)
{
return detail::convertWindowsToCarbonitePath<std::string>(pathW);
}
inline std::string convertWindowsToCarbonitePath(cpp::unbounded_wstring path)
{
return convertWindowsToCarbonitePath(cpp::wstring_view(cpp::unsafe_length, path));
}
inline std::wstring fixWindowsPathPrefix(std::wstring pathW)
{
const bool hasPrefix = pathW.compare(0, kLongPathPrefix.size(), kLongPathPrefix) == 0;
if (!hasPrefix && pathW.size() >= CARBWIN_MAX_PATH)
return join(kLongPathPrefix, std::move(pathW));
if (hasPrefix && pathW.size() < CARBWIN_MAX_PATH)
pathW.erase(0, kLongPathPrefix.size());
return pathW;
}
inline omni::expected<std::wstring, HRESULT> getWindowsCanonicalPathEx(cpp::wzstring_view path)
{
wchar_t* canonical = nullptr;
if (auto hr = PathAllocCanonicalize(path.c_str(), CARBWIN_PATHCCH_ALLOW_LONG_PATHS, &canonical);
!CARBWIN_SUCCEEDED(hr))
{
return omni::unexpected(hr);
}
std::wstring result(canonical);
LocalFree(canonical);
return result;
}
inline std::wstring getWindowsCanonicalPath(const std::wstring& pathW)
{
wchar_t* canonical = nullptr;
auto hr = PathAllocCanonicalize(pathW.c_str(), CARBWIN_PATHCCH_ALLOW_LONG_PATHS, &canonical);
if (CARBWIN_SUCCEEDED(hr))
{
std::wstring result = canonical;
LocalFree(canonical);
return result;
}
(void)carb::detail::setError(
ErrorCode::kFail, omni::string{ omni::formatted, "PathAllocCanonicalize failed with HRESULT 0x%08x", hr });
return pathW;
}
inline std::wstring getWindowsFullPath(const std::wstring& pathW)
{
// Retrieve the size
DWORD size = GetFullPathNameW(pathW.c_str(), 0, nullptr, nullptr);
if (size != 0)
{
std::wstring fullPathName(size - 1, '\0');
size = GetFullPathNameW(pathW.c_str(), size, &fullPathName[0], nullptr);
if (size)
{
// Assert if the Win32 API lied to us. Note that sometimes it does use less than asked for.
CARB_ASSERT(size <= fullPathName.size());
fullPathName.resize(size);
return fullPathName;
}
}
ErrorApi::setFromWinApiErrorCode();
return pathW;
}
inline void adjustWindowsDllSearchPaths()
{
// MSDN:
// https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-setdefaultdlldirectories
// LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
// This value is a combination of LOAD_LIBRARY_SEARCH_APPLICATION_DIR, LOAD_LIBRARY_SEARCH_SYSTEM32, and
// LOAD_LIBRARY_SEARCH_USER_DIRS.
SetDefaultDllDirectories(CARBWIN_LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
}
} // namespace carb::extras
#endif