Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update joinPaths implementation in InstallationDirectories #1469

Merged
merged 1 commit into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME}
PRIVATE
TINYXML2::TINYXML2)

if (WIN32)
target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME}
PRIVATE shlwapi)
endif()

if (USE_INTERNAL_URDF)
target_include_directories(${PROJECT_LIBRARY_TARGET_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/urdf)
Expand Down
89 changes: 34 additions & 55 deletions src/InstallationDirectories.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@
*
*/

#include <filesystem>
#include <regex>

#include <sdf/sdf_config.h>
#include <sdf/InstallationDirectories.hh>

#ifdef _WIN32
#include <shlwapi.h>
#endif

namespace sdf
{
inline namespace SDF_VERSION_NAMESPACE {
Expand Down Expand Up @@ -75,70 +72,52 @@ std::string checkWindowsPath(const std::string _path)
}

// Function imported from
// https://github.com/gazebosim/gz-common/blob/ignition-common4_4.6.2/src/Filesystem.cc#L256
// https://github.com/gazebosim/gz-common/blob/gz-common5_5.6.0/src/Filesystem.cc#L142
std::string joinPaths(const std::string &_path1,
const std::string &_path2)
{
namespace fs = std::filesystem;
fs::path p1{_path1};
fs::path p2{_path2};

/// This function is used to avoid duplicated path separators at the
/// beginning/end of the string, and between the two paths being joined.
/// \param[in] _path This is the string to sanitize.
/// \param[in] _stripLeading True if the leading separator should be
/// removed.
auto sanitizeSlashes = [](const std::string &_path,
bool _stripLeading = false)
if (p1.empty())
{
// Shortcut
if (_path.empty())
return _path;
p1 = std::string{fs::path::preferred_separator};
}

std::string result = _path;
bool is_url = false;

// Use the appropriate character for each platform.
#ifndef _WIN32
char replacement = '/';
#else
char replacement = '\\';
#endif
if (_path1.find("://") == std::string::npos)
p1 = p1.lexically_normal();
else
is_url = true;

// TODO(mjcarroll) Address the case that path2 is also a URI.
// It's likely not a valid scenario, but not currently covered by our test
// suite and doesn't return an error.
if (_path2.find("://") == std::string::npos)
p2 = p2.lexically_normal();
else
is_url = true;

if (p2.string()[0] == fs::path::preferred_separator)
{
p2 = fs::path{p2.string().substr(1)};
}

auto ret = (p1 / p2);

// Sanitize the start of the path.
size_t index = 0;
size_t leadingIndex = _stripLeading ? 0 : 1;
for (; index < result.length() && result[index] == replacement; ++index)
{
}
if (index > leadingIndex)
result.erase(leadingIndex, index-leadingIndex);

// Sanitize the end of the path.
index = result.length()-1;
for (; index < result.length() && result[index] == replacement; --index)
{
}
index += 1;
if (index < result.length()-1)
result.erase(index+1);
return result;
};

std::string path;
#ifndef _WIN32
path = sanitizeSlashes(sanitizeSlashes(separator(_path1)) +
sanitizeSlashes(_path2, true));
#else // _WIN32
std::string path1 = sanitizeSlashes(checkWindowsPath(_path1));
std::string path2 = sanitizeSlashes(checkWindowsPath(_path2), true);
std::vector<char> combined(path1.length() + path2.length() + 2);
if (::PathCombineA(combined.data(), path1.c_str(), path2.c_str()) != NULL)
if (is_url)
{
path = sanitizeSlashes(checkWindowsPath(std::string(combined.data())));
std::string path = ret.string();
std::replace(path.begin(), path.end(),
static_cast<char>(fs::path::preferred_separator), '/');
return path;
}
else
{
path = sanitizeSlashes(checkWindowsPath(separator(path1) + path2));
return ret.lexically_normal().string();
}
#endif // _WIN32
return path;
}

std::string getSharePath()
Expand Down
Loading