Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/util/util_path.cpp')
-rw-r--r--intern/cycles/util/util_path.cpp631
1 files changed, 573 insertions, 58 deletions
diff --git a/intern/cycles/util/util_path.cpp b/intern/cycles/util/util_path.cpp
index e8f1ec81763..83754728dbe 100644
--- a/intern/cycles/util/util_path.cpp
+++ b/intern/cycles/util/util_path.cpp
@@ -19,30 +19,299 @@
#include "util_path.h"
#include "util_string.h"
+#include <OpenImageIO/filesystem.h>
#include <OpenImageIO/strutil.h>
#include <OpenImageIO/sysutil.h>
+
OIIO_NAMESPACE_USING
#include <stdio.h>
-#include <boost/filesystem.hpp>
-#include <boost/algorithm/string.hpp>
+#include <sys/stat.h>
+
+#if defined(_WIN32)
+# define DIR_SEP '\\'
+# define DIR_SEP_ALT '/'
+# include <direct.h>
+#else
+# define DIR_SEP '/'
+# include <dirent.h>
+#endif
+
+#ifdef HAVE_SHLWAPI_H
+# include <shlwapi.h>
+#endif
+
+#include "util_windows.h"
CCL_NAMESPACE_BEGIN
+#ifdef _WIN32
+# if defined(_MSC_VER) || defined(__MINGW64__)
+typedef struct _stat64 path_stat_t;
+# elif defined(__MINGW32__)
+typedef struct _stati64 path_stat_t;
+# else
+typedef struct _stat path_stat_t;
+# endif
+# ifndef S_ISDIR
+# define S_ISDIR(x) (((x) & _S_IFDIR) == _S_IFDIR)
+# endif
+#else
+typedef struct stat path_stat_t;
+#endif
+
static string cached_path = "";
static string cached_user_path = "";
-static boost::filesystem::path to_boost(const string& path)
-{
- return boost::filesystem::path(path.c_str());
-}
+namespace {
+
+#ifdef _WIN32
+class directory_iterator {
+public:
+ class path_info {
+ public:
+ path_info(const string& path,
+ const WIN32_FIND_DATAW& find_data)
+ : path_(path),
+ find_data_(find_data)
+ {
+ }
-static string from_boost(const boost::filesystem::path& path)
+ string path() {
+ return path_join(path_, string_from_wstring(find_data_.cFileName));
+ }
+ protected:
+ const string& path_;
+ const WIN32_FIND_DATAW& find_data_;
+ };
+
+ directory_iterator()
+ : path_info_("", find_data_),
+ h_find_(INVALID_HANDLE_VALUE)
+ {
+ }
+
+ directory_iterator(const string& path)
+ : path_(path),
+ path_info_(path, find_data_)
+ {
+ string wildcard = path;
+ if(wildcard[wildcard.size() - 1] != DIR_SEP) {
+ wildcard += DIR_SEP;
+ }
+ wildcard += "*";
+ h_find_ = FindFirstFileW(string_to_wstring(wildcard).c_str(),
+ &find_data_);
+ if(h_find_ != INVALID_HANDLE_VALUE) {
+ skip_dots();
+ }
+ }
+
+ ~directory_iterator()
+ {
+ if(h_find_ != INVALID_HANDLE_VALUE) {
+ FindClose(h_find_);
+ }
+ }
+
+ directory_iterator& operator++()
+ {
+ step();
+ return *this;
+ }
+
+ path_info* operator-> ()
+ {
+ return &path_info_;
+ }
+
+ bool operator!=(const directory_iterator& other)
+ {
+ return h_find_ != other.h_find_;
+ }
+
+protected:
+ bool step()
+ {
+ if(do_step()) {
+ return skip_dots();
+ }
+ return false;
+ }
+
+ bool do_step()
+ {
+ if(h_find_ != INVALID_HANDLE_VALUE) {
+ bool result = FindNextFileW(h_find_, &find_data_) == TRUE;
+ if(!result) {
+ FindClose(h_find_);
+ h_find_ = INVALID_HANDLE_VALUE;
+ }
+ return result;
+ }
+ return false;
+ }
+
+ bool skip_dots()
+ {
+ while(wcscmp(find_data_.cFileName, L".") == 0 ||
+ wcscmp(find_data_.cFileName, L"..") == 0)
+ {
+ if(!do_step()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ string path_;
+ path_info path_info_;
+ WIN32_FIND_DATAW find_data_;
+ HANDLE h_find_;
+};
+#else /* _WIN32 */
+
+class directory_iterator {
+public:
+ class path_info {
+ public:
+ path_info(const string& path)
+ : path_(path),
+ entry_(NULL)
+ {
+ }
+
+ string path() {
+ return path_join(path_, entry_->d_name);
+ }
+
+ void current_entry_set(const struct dirent *entry)
+ {
+ entry_ = entry;
+ }
+ protected:
+ const string& path_;
+ const struct dirent *entry_;
+ };
+
+ directory_iterator()
+ : path_info_(""),
+ name_list_(NULL),
+ num_entries_(-1),
+ cur_entry_(-1)
+ {
+ }
+
+ directory_iterator(const string& path)
+ : path_(path),
+ path_info_(path_),
+ cur_entry_(0)
+ {
+ num_entries_ = scandir(path.c_str(),
+ &name_list_,
+ NULL,
+ alphasort);
+ if(num_entries_ < 0) {
+ perror("scandir");
+ }
+ else {
+ skip_dots();
+ }
+ }
+
+ ~directory_iterator()
+ {
+ destroy_name_list();
+ }
+
+ directory_iterator& operator++()
+ {
+ step();
+ return *this;
+ }
+
+ path_info* operator-> ()
+ {
+ path_info_.current_entry_set(name_list_[cur_entry_]);
+ return &path_info_;
+ }
+
+ bool operator!=(const directory_iterator& other)
+ {
+ return name_list_ != other.name_list_;
+ }
+
+protected:
+ bool step()
+ {
+ if(do_step()) {
+ return skip_dots();
+ }
+ return false;
+ }
+
+ bool do_step()
+ {
+ ++cur_entry_;
+ if(cur_entry_ >= num_entries_) {
+ destroy_name_list();
+ return false;
+ }
+ return true;
+ }
+
+ /* Skip . and .. folders. */
+ bool skip_dots()
+ {
+ while(strcmp(name_list_[cur_entry_]->d_name, ".") == 0 ||
+ strcmp(name_list_[cur_entry_]->d_name, "..") == 0)
+ {
+ if(!step()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void destroy_name_list()
+ {
+ if(name_list_ == NULL) {
+ return;
+ }
+ for(int i = 0; i < num_entries_; ++i) {
+ free(name_list_[i]);
+ }
+ free(name_list_);
+ name_list_ = NULL;
+ }
+
+ string path_;
+ path_info path_info_;
+ struct dirent **name_list_;
+ int num_entries_, cur_entry_;
+};
+
+#endif /* _WIN32 */
+
+size_t find_last_slash(const string& path)
{
- return path.string().c_str();
+ for(size_t i = 0; i < path.size(); ++i) {
+ size_t index = path.size() - 1 - i;
+#ifdef _WIN32
+ if(path[index] == DIR_SEP || path[index] == DIR_SEP_ALT)
+#else
+ if(path[index] == DIR_SEP)
+#endif
+ {
+ return index;
+ }
+ }
+ return string::npos;
}
+} /* namespace */
+
static char *path_specials(const string& sub)
{
static bool env_init = false;
@@ -68,8 +337,10 @@ void path_init(const string& path, const string& user_path)
cached_user_path = user_path;
#ifdef _MSC_VER
- // fix for https://svn.boost.org/trac/boost/ticket/6320
- boost::filesystem::path::imbue( std::locale( "" ) );
+ // workaround for https://svn.boost.org/trac/boost/ticket/6320
+ // indirectly init boost codec here since it's not thread safe, and can
+ // cause crashes when it happens in multithreaded image load
+ OIIO::Filesystem::exists(path);
#endif
}
@@ -95,49 +366,237 @@ string path_user_get(const string& sub)
string path_filename(const string& path)
{
- return from_boost(to_boost(path).filename());
+ size_t index = find_last_slash(path);
+ if(index != string::npos) {
+ /* Corner cases to match boost behavior. */
+#ifndef _WIN32
+ if(index == 0 && path.size() == 1) {
+ return path;
+ }
+#endif
+ if(index == path.size() - 1) {
+#ifdef _WIN32
+ if(index == 2) {
+ return string(1, DIR_SEP);
+ }
+#endif
+ return ".";
+ }
+ return path.substr(index + 1, path.size() - index - 1);
+ }
+ return path;
}
string path_dirname(const string& path)
{
- return from_boost(to_boost(path).parent_path());
+ size_t index = find_last_slash(path);
+ if(index != string::npos) {
+#ifndef _WIN32
+ if(index == 0 && path.size() > 1) {
+ return string(1, DIR_SEP);
+ }
+#endif
+ return path.substr(0, index);
+ }
+ return "";
}
string path_join(const string& dir, const string& file)
{
- return from_boost((to_boost(dir) / to_boost(file)));
+ if(dir.size() == 0) {
+ return file;
+ }
+ if(file.size() == 0) {
+ return dir;
+ }
+ string result = dir;
+#ifndef _WIN32
+ if(result[result.size() - 1] != DIR_SEP &&
+ file[0] != DIR_SEP)
+#else
+ if(result[result.size() - 1] != DIR_SEP &&
+ result[result.size() - 1] != DIR_SEP_ALT &&
+ file[0] != DIR_SEP &&
+ file[0] != DIR_SEP_ALT)
+#endif
+ {
+ result += DIR_SEP;
+ }
+ result += file;
+ return result;
}
string path_escape(const string& path)
{
string result = path;
- boost::replace_all(result, " ", "\\ ");
+ string_replace(result, " ", "\\ ");
return result;
}
bool path_is_relative(const string& path)
{
- return to_boost(path).is_relative();
+#ifdef _WIN32
+# ifdef HAVE_SHLWAPI_H
+ return PathIsRelative(path.c_str());
+# else /* HAVE_SHLWAPI_H */
+ if(path.size() >= 3) {
+ return !(((path[0] >= 'a' && path[0] <= 'z') ||
+ (path[0] >= 'A' && path[0] <= 'Z')) &&
+ path[1] == ':' && path[2] == DIR_SEP);
+ }
+ return true;
+# endif /* HAVE_SHLWAPI_H */
+#else /* _WIN32 */
+ if(path.size() == 0) {
+ return 1;
+ }
+ return path[0] != DIR_SEP;
+#endif /* _WIN32 */
+}
+
+#ifdef _WIN32
+/* Add a slash if the UNC path points to a share. */
+static string path_unc_add_slash_to_share(const string& path)
+{
+ size_t slash_after_server = path.find(DIR_SEP, 2);
+ if(slash_after_server != string::npos) {
+ size_t slash_after_share = path.find(DIR_SEP,
+ slash_after_server + 1);
+ if(slash_after_share == string::npos) {
+ return path + DIR_SEP;
+ }
+ }
+ return path;
+}
+
+/* Convert:
+ * \\?\UNC\server\share\folder\... to \\server\share\folder\...
+ * \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
+ */
+static string path_unc_to_short(const string& path)
+{
+ size_t len = path.size();
+ if((len > 3) &&
+ (path[0] == DIR_SEP) &&
+ (path[1] == DIR_SEP) &&
+ (path[2] == '?') &&
+ ((path[3] == DIR_SEP) || (path[3] == DIR_SEP_ALT)))
+ {
+ if((len > 5) && (path[5] == ':')) {
+ return path.substr(4, len - 4);
+ }
+ else if((len > 7) &&
+ (path.substr(4, 3) == "UNC") &&
+ ((path[7] == DIR_SEP) || (path[7] == DIR_SEP_ALT)))
+ {
+ return "\\\\" + path.substr(8, len - 8);
+ }
+ }
+ return path;
+}
+
+static string path_cleanup_unc(const string& path)
+{
+ string result = path_unc_to_short(path);
+ if(path.size() > 2) {
+ /* It's possible path is now a non-UNC. */
+ if(result[0] == DIR_SEP && result[1] == DIR_SEP) {
+ return path_unc_add_slash_to_share(result);
+ }
+ }
+ return result;
+}
+
+/* Make path compatible for stat() functions. */
+static string path_make_compatible(const string& path)
+{
+ string result = path;
+ /* In Windows stat() doesn't recognize dir ending on a slash. */
+ if(result.size() > 3 && result[result.size() - 1] == DIR_SEP) {
+ result.resize(result.size() - 1);
+ }
+ /* Clean up UNC path. */
+ if((path.size() >= 3) && (path[0] == DIR_SEP) && (path[1] == DIR_SEP)) {
+ result = path_cleanup_unc(result);
+ }
+ /* Make sure volume-only path ends up wit ha directory separator. */
+ if(result.size() == 2 && result[1] == ':') {
+ result += DIR_SEP;
+ }
+ return result;
+}
+
+static int path_wstat(const wstring& path_wc, path_stat_t *st)
+{
+#if defined(_MSC_VER) || defined(__MINGW64__)
+ return _wstat64(path_wc.c_str(), st);
+#elif defined(__MINGW32__)
+ return _wstati64(path_wc.c_str(), st);
+#else
+ return _wstat(path_wc.c_str(), st);
+#endif
+}
+
+static int path_stat(const string& path, path_stat_t *st)
+{
+ wstring path_wc = string_to_wstring(path);
+ return path_wstat(path_wc, st);
+}
+#else /* _WIN32 */
+static int path_stat(const string& path, path_stat_t *st)
+{
+ return stat(path.c_str(), st);
+}
+#endif /* _WIN32 */
+
+size_t path_file_size(const string& path)
+{
+ path_stat_t st;
+ if(path_stat(path, &st) != 0) {
+ return -1;
+ }
+ return st.st_size;
}
bool path_exists(const string& path)
{
- return boost::filesystem::exists(to_boost(path));
+#ifdef _WIN32
+ string fixed_path = path_make_compatible(path);
+ wstring path_wc = string_to_wstring(fixed_path);
+ path_stat_t st;
+ if(path_wstat(path_wc, &st) != 0) {
+ return false;
+ }
+ return st.st_mode != 0;
+#else /* _WIN32 */
+ struct stat st;
+ if(stat(path.c_str(), &st) != 0) {
+ return 0;
+ }
+ return st.st_mode != 0;
+#endif /* _WIN32 */
}
-static void path_files_md5_hash_recursive(MD5Hash& hash, const string& dir)
+bool path_is_directory(const string& path)
{
- boost::filesystem::path dirpath = to_boost(dir);
+ path_stat_t st;
+ if(path_stat(path, &st) != 0) {
+ return false;
+ }
+ return S_ISDIR(st.st_mode);
+}
- if(boost::filesystem::exists(dirpath)) {
- boost::filesystem::directory_iterator it(dirpath), it_end;
+static void path_files_md5_hash_recursive(MD5Hash& hash, const string& dir)
+{
+ if(path_exists(dir)) {
+ directory_iterator it(dir), it_end;
- for(; it != it_end; it++) {
- if(boost::filesystem::is_directory(it->status())) {
- path_files_md5_hash_recursive(hash, from_boost(it->path()));
+ for(; it != it_end; ++it) {
+ if(path_is_directory(it->path())) {
+ path_files_md5_hash_recursive(hash, it->path());
}
else {
- string filepath = from_boost(it->path());
+ string filepath = it->path();
hash.append((const uint8_t*)filepath.c_str(), filepath.size());
hash.append_file(filepath);
@@ -156,9 +615,36 @@ string path_files_md5_hash(const string& dir)
return hash.get_hex();
}
-void path_create_directories(const string& path)
+static bool create_directories_recursivey(const string& path)
+{
+ if(path_is_directory(path)) {
+ /* Directory already exists, nothing to do. */
+ return true;
+ }
+ if(path_exists(path)) {
+ /* File exists and it's not a directory. */
+ return false;
+ }
+
+ string parent = path_dirname(path);
+ if(parent.size() > 0 && parent != path) {
+ if(!create_directories_recursivey(parent)) {
+ return false;
+ }
+ }
+
+#ifdef _WIN32
+ wstring path_wc = string_to_wstring(path);
+ return _wmkdir(path_wc.c_str()) == 0;
+#else
+ return mkdir(path.c_str(), 0777) == 0;
+#endif
+}
+
+void path_create_directories(const string& filepath)
{
- boost::filesystem::create_directories(to_boost(path_dirname(path)));
+ string path = path_dirname(filepath);
+ create_directories_recursivey(path);
}
bool path_write_binary(const string& path, const vector<uint8_t>& binary)
@@ -189,13 +675,15 @@ bool path_write_text(const string& path, string& text)
bool path_read_binary(const string& path, vector<uint8_t>& binary)
{
- binary.resize(boost::filesystem::file_size(to_boost(path)));
-
/* read binary file into memory */
FILE *f = path_fopen(path, "rb");
- if(!f)
+ if(!f) {
+ binary.resize(0);
return false;
+ }
+
+ binary.resize(path_file_size(path));
if(binary.size() == 0) {
fclose(f);
@@ -228,57 +716,84 @@ bool path_read_text(const string& path, string& text)
uint64_t path_modified_time(const string& path)
{
- if(boost::filesystem::exists(to_boost(path)))
- return (uint64_t)boost::filesystem::last_write_time(to_boost(path));
-
+ path_stat_t st;
+ if(path_stat(path, &st) != 0) {
+ return st.st_mtime;
+ }
return 0;
}
-string path_source_replace_includes(const string& source_, const string& path)
+bool path_remove(const string& path)
{
- /* our own little c preprocessor that replaces #includes with the file
- * contents, to work around issue of opencl drivers not supporting
- * include paths with spaces in them */
- string source = source_;
- const string include = "#include \"";
- size_t n, pos = 0;
-
- while((n = source.find(include, pos)) != string::npos) {
- size_t n_start = n + include.size();
- size_t n_end = source.find("\"", n_start);
- string filename = source.substr(n_start, n_end - n_start);
-
- string text, filepath = path_join(path, filename);
+ return remove(path.c_str()) == 0;
+}
- if(path_read_text(filepath, text)) {
- text = path_source_replace_includes(text, path_dirname(filepath));
- source.replace(n, n_end + 1 - n, "\n" + text + "\n");
+string path_source_replace_includes(const string& source, const string& path)
+{
+ /* Our own little c preprocessor that replaces #includes with the file
+ * contents, to work around issue of opencl drivers not supporting
+ * include paths with spaces in them.
+ */
+
+ string result = "";
+ vector<string> lines;
+ string_split(lines, source, "\n");
+
+ for(size_t i = 0; i < lines.size(); ++i) {
+ string line = lines[i];
+ if(line[0] == '#') {
+ string token = string_strip(line.substr(1, line.size() - 1));
+ if(string_startswith(token, "include")) {
+ token = string_strip(token.substr(7, token.size() - 7));
+ if(token[0] == '"') {
+ size_t n_start = 1;
+ size_t n_end = token.find("\"", n_start);
+ string filename = token.substr(n_start, n_end - n_start);
+ string text, filepath = path_join(path, filename);
+ if(path_read_text(filepath, text)) {
+ /* Replace include directories with both current path
+ * and path extracted from the include file.
+ * Not totally robust, but works fine for Cycles kernel
+ * and avoids having list of include directories.x
+ */
+ text = path_source_replace_includes(
+ text, path_dirname(filepath));
+ text = path_source_replace_includes(text, path);
+ line = token.replace(0, n_end + 1, "\n" + text + "\n");
+ }
+ }
+ }
}
- else
- pos = n_end;
+ result += line + "\n";
}
- return source;
+ return result;
}
FILE *path_fopen(const string& path, const string& mode)
{
+#ifdef _WIN32
+ wstring path_wc = string_to_wstring(path);
+ wstring mode_wc = string_to_wstring(mode);
+ return _wfopen(path_wc.c_str(), mode_wc.c_str());
+#else
return fopen(path.c_str(), mode.c_str());
+#endif
}
void path_cache_clear_except(const string& name, const set<string>& except)
{
string dir = path_user_get("cache");
- if(boost::filesystem::exists(dir)) {
- boost::filesystem::directory_iterator it(dir), it_end;
+ if(path_exists(dir)) {
+ directory_iterator it(dir), it_end;
- for(; it != it_end; it++) {
- string filename = from_boost(it->path().filename().string());
+ for(; it != it_end; ++it) {
+ string filename = path_filename(it->path());
- if(boost::starts_with(filename, name))
+ if(string_startswith(filename, name.c_str()))
if(except.find(filename) == except.end())
- boost::filesystem::remove(to_boost(filename));
+ path_remove(it->path());
}
}