Path: blob/master/thirdparty/openxr/src/common/filesystem_utils.cpp
9903 views
// Copyright (c) 2017-2025 The Khronos Group Inc.1// Copyright (c) 2017 Valve Corporation2// Copyright (c) 2017 LunarG, Inc.3//4// SPDX-License-Identifier: Apache-2.0 OR MIT5//6// Initial Authors: Mark Young <[email protected]>7// Nat Brown <[email protected]>8//910#include "filesystem_utils.hpp"1112#include "platform_utils.hpp"1314#include <cstring>15#include <string>1617#if defined DISABLE_STD_FILESYSTEM18#define USE_EXPERIMENTAL_FS 019#define USE_FINAL_FS 02021#else22#include "stdfs_conditions.h"23#endif2425#if USE_FINAL_FS == 126#include <filesystem>27#define FS_PREFIX std::filesystem28#elif USE_EXPERIMENTAL_FS == 129#include <experimental/filesystem>30#define FS_PREFIX std::experimental::filesystem31#elif defined(XR_USE_PLATFORM_WIN32)32// Windows fallback includes33#include <stdint.h>34#include <direct.h>35#else36// Linux/Apple fallback includes37#include <sys/stat.h>38#include <unistd.h>39#include <limits.h>40#include <stdlib.h>41#include <dirent.h>42#endif4344#if defined(XR_USE_PLATFORM_WIN32)45#define PATH_SEPARATOR ';'46#define DIRECTORY_SYMBOL '\\'47#define ALTERNATE_DIRECTORY_SYMBOL '/'48#else49#define PATH_SEPARATOR ':'50#define DIRECTORY_SYMBOL '/'51#endif5253#if (USE_FINAL_FS == 1) || (USE_EXPERIMENTAL_FS == 1)54// We can use one of the C++ filesystem packages5556bool FileSysUtilsIsRegularFile(const std::string& path) { return FS_PREFIX::is_regular_file(path); }5758bool FileSysUtilsIsDirectory(const std::string& path) { return FS_PREFIX::is_directory(path); }5960bool FileSysUtilsPathExists(const std::string& path) { return FS_PREFIX::exists(path); }6162bool FileSysUtilsIsAbsolutePath(const std::string& path) {63FS_PREFIX::path file_path(path);64return file_path.is_absolute();65}6667bool FileSysUtilsGetCurrentPath(std::string& path) {68FS_PREFIX::path cur_path = FS_PREFIX::current_path();69path = cur_path.string();70return true;71}7273bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {74FS_PREFIX::path path_var(file_path);75parent_path = path_var.parent_path().string();76return true;77}7879bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {80absolute = FS_PREFIX::absolute(path).string();81return true;82}8384bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& canonical) {85#if defined(XR_USE_PLATFORM_WIN32)86// std::filesystem::canonical fails on UWP and must be avoided. Further, PathCchCanonicalize is not available on Windows 7 and87// PathCanonicalizeW is not available on UWP. However, symbolic links are not important on Windows since the loader uses the88// registry for indirection instead, and so this function can be a no-op on Windows.89canonical = path;90#else91canonical = FS_PREFIX::canonical(path).string();92#endif93return true;94}9596bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {97FS_PREFIX::path parent_path(parent);98FS_PREFIX::path child_path(child);99FS_PREFIX::path full_path = parent_path / child_path;100combined = full_path.string();101return true;102}103104bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {105std::string::size_type start = 0;106std::string::size_type location = path_list.find(PATH_SEPARATOR);107while (location != std::string::npos) {108paths.push_back(path_list.substr(start, location));109start = location + 1;110location = path_list.find(PATH_SEPARATOR, start);111}112paths.push_back(path_list.substr(start, location));113return true;114}115116bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {117for (auto& dir_iter : FS_PREFIX::directory_iterator(path)) {118files.push_back(dir_iter.path().filename().string());119}120return true;121}122123#elif defined(XR_OS_WINDOWS)124125// For pre C++17 compiler that doesn't support experimental filesystem126127bool FileSysUtilsIsRegularFile(const std::string& path) {128const DWORD attr = GetFileAttributesW(utf8_to_wide(path).c_str());129return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);130}131132bool FileSysUtilsIsDirectory(const std::string& path) {133const DWORD attr = GetFileAttributesW(utf8_to_wide(path).c_str());134return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);135}136137bool FileSysUtilsPathExists(const std::string& path) {138return (GetFileAttributesW(utf8_to_wide(path).c_str()) != INVALID_FILE_ATTRIBUTES);139}140141bool FileSysUtilsIsAbsolutePath(const std::string& path) {142bool pathStartsWithDir = (path.size() >= 1) && ((path[0] == DIRECTORY_SYMBOL) || (path[0] == ALTERNATE_DIRECTORY_SYMBOL));143144bool pathStartsWithDrive =145(path.size() >= 3) && (path[1] == ':' && (path[2] == DIRECTORY_SYMBOL || path[2] == ALTERNATE_DIRECTORY_SYMBOL));146147return pathStartsWithDir || pathStartsWithDrive;148}149150bool FileSysUtilsGetCurrentPath(std::string& path) {151wchar_t tmp_path[MAX_PATH];152if (nullptr != _wgetcwd(tmp_path, MAX_PATH - 1)) {153path = wide_to_utf8(tmp_path);154return true;155}156return false;157}158159bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {160std::string full_path;161if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {162std::string::size_type lastSeparator = full_path.find_last_of(DIRECTORY_SYMBOL);163parent_path = (lastSeparator == 0) ? full_path : full_path.substr(0, lastSeparator);164return true;165}166return false;167}168169bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {170wchar_t tmp_path[MAX_PATH];171if (0 != GetFullPathNameW(utf8_to_wide(path).c_str(), MAX_PATH, tmp_path, NULL)) {172absolute = wide_to_utf8(tmp_path);173return true;174}175return false;176}177178bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& absolute) {179// PathCchCanonicalize is not available on Windows 7 and PathCanonicalizeW is not available on UWP. However, symbolic links are180// not important on Windows since the loader uses the registry for indirection instead, and so this function can be a no-op on181// Windows.182absolute = path;183return true;184}185186bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {187std::string::size_type parent_len = parent.length();188if (0 == parent_len || "." == parent || ".\\" == parent || "./" == parent) {189combined = child;190return true;191}192char last_char = parent[parent_len - 1];193if ((last_char == DIRECTORY_SYMBOL) || (last_char == ALTERNATE_DIRECTORY_SYMBOL)) {194parent_len--;195}196combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;197return true;198}199200bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {201std::string::size_type start = 0;202std::string::size_type location = path_list.find(PATH_SEPARATOR);203while (location != std::string::npos) {204paths.push_back(path_list.substr(start, location));205start = location + 1;206location = path_list.find(PATH_SEPARATOR, start);207}208paths.push_back(path_list.substr(start, location));209return true;210}211212bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {213std::string searchPath;214FileSysUtilsCombinePaths(path, "*", searchPath);215216WIN32_FIND_DATAW file_data;217HANDLE file_handle = FindFirstFileW(utf8_to_wide(searchPath).c_str(), &file_data);218if (file_handle != INVALID_HANDLE_VALUE) {219do {220if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {221files.push_back(wide_to_utf8(file_data.cFileName));222}223} while (FindNextFileW(file_handle, &file_data));224return true;225}226return false;227}228229#else // XR_OS_LINUX/XR_OS_APPLE fallback230231// simple POSIX-compatible implementation of the <filesystem> pieces used by OpenXR232233bool FileSysUtilsIsRegularFile(const std::string& path) {234struct stat path_stat;235stat(path.c_str(), &path_stat);236return S_ISREG(path_stat.st_mode);237}238239bool FileSysUtilsIsDirectory(const std::string& path) {240struct stat path_stat;241stat(path.c_str(), &path_stat);242return S_ISDIR(path_stat.st_mode);243}244245bool FileSysUtilsPathExists(const std::string& path) { return (access(path.c_str(), F_OK) != -1); }246247bool FileSysUtilsIsAbsolutePath(const std::string& path) { return (path[0] == DIRECTORY_SYMBOL); }248249bool FileSysUtilsGetCurrentPath(std::string& path) {250char tmp_path[PATH_MAX];251if (nullptr != getcwd(tmp_path, PATH_MAX - 1)) {252path = tmp_path;253return true;254}255return false;256}257258bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {259std::string full_path;260if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {261std::string::size_type lastSeparator = full_path.find_last_of(DIRECTORY_SYMBOL);262parent_path = (lastSeparator == 0) ? full_path : full_path.substr(0, lastSeparator);263return true;264}265return false;266}267268bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {269// canonical path is absolute270return FileSysUtilsGetCanonicalPath(path, absolute);271}272273bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& canonical) {274char buf[PATH_MAX];275if (nullptr != realpath(path.c_str(), buf)) {276canonical = buf;277return true;278}279return false;280}281282bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {283std::string::size_type parent_len = parent.length();284if (0 == parent_len || "." == parent || "./" == parent) {285combined = child;286return true;287}288char last_char = parent[parent_len - 1];289if (last_char == DIRECTORY_SYMBOL) {290parent_len--;291}292combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;293return true;294}295296bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {297std::string::size_type start = 0;298std::string::size_type location = path_list.find(PATH_SEPARATOR);299while (location != std::string::npos) {300paths.push_back(path_list.substr(start, location));301start = location + 1;302location = path_list.find(PATH_SEPARATOR, start);303}304paths.push_back(path_list.substr(start, location));305return true;306}307308bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {309DIR* dir = opendir(path.c_str());310if (dir == nullptr) {311return false;312}313struct dirent* entry;314while ((entry = readdir(dir)) != nullptr) {315files.emplace_back(entry->d_name);316}317closedir(dir);318return true;319}320321#endif322323324