12#include <OpenImageIO/filesystem.h>
13#include <OpenImageIO/strutil.h>
14#include <OpenImageIO/sysutil.h>
26# define DIR_SEP_ALT '/'
32# include <sys/types.h>
46# if defined(_MSC_VER) || defined(__MINGW64__)
48# elif defined(__MINGW32__)
54# define S_ISDIR(x) (((x) & _S_IFDIR) == _S_IFDIR)
67class directory_iterator {
71 path_info(
const string &path,
const WIN32_FIND_DATAW &find_data)
72 : path_(path), find_data_(find_data)
78 return path_join(path_, string_from_wstring(find_data_.cFileName));
83 const WIN32_FIND_DATAW &find_data_;
86 directory_iterator() : path_info_(
"", find_data_), h_find_(INVALID_HANDLE_VALUE) {}
88 explicit directory_iterator(
const string &path) : path_(path), path_info_(path, find_data_)
90 string wildcard = path;
91 if (wildcard[wildcard.size() - 1] !=
DIR_SEP) {
95 h_find_ = FindFirstFileW(string_to_wstring(wildcard).c_str(), &find_data_);
96 if (h_find_ != INVALID_HANDLE_VALUE) {
101 ~directory_iterator()
103 if (h_find_ != INVALID_HANDLE_VALUE) {
114 path_info *operator->()
119 bool operator!=(
const directory_iterator &other)
121 return h_find_ != other.h_find_;
135 if (h_find_ != INVALID_HANDLE_VALUE) {
136 bool result = FindNextFileW(h_find_, &find_data_) == TRUE;
139 h_find_ = INVALID_HANDLE_VALUE;
148 while (wcscmp(find_data_.cFileName,
L".") == 0 || wcscmp(find_data_.cFileName,
L"..") == 0) {
157 path_info path_info_;
158 WIN32_FIND_DATAW find_data_;
163class directory_iterator {
167 explicit path_info(
const string &path) : path_(path), entry_(
NULL) {}
174 void current_entry_set(
const struct dirent *entry)
181 const struct dirent *entry_;
184 directory_iterator() : path_info_(
""), name_list_(
NULL), num_entries_(-1), cur_entry_(-1) {}
186 explicit directory_iterator(
const string &path) : path_(path), path_info_(path_), cur_entry_(0)
188 num_entries_ = scandir(path.c_str(), &name_list_,
NULL, alphasort);
189 if (num_entries_ < 0) {
197 ~directory_iterator()
208 path_info *operator->()
210 path_info_.current_entry_set(name_list_[cur_entry_]);
214 bool operator!=(
const directory_iterator &other)
216 return name_list_ != other.name_list_;
231 if (cur_entry_ >= num_entries_) {
241 while (strcmp(name_list_[cur_entry_]->d_name,
".") == 0 ||
242 strcmp(name_list_[cur_entry_]->d_name,
"..") == 0)
251 void destroy_name_list()
253 if (name_list_ ==
NULL) {
256 for (
int i = 0; i < num_entries_; ++i) {
264 path_info path_info_;
265 struct dirent **name_list_;
266 int num_entries_, cur_entry_;
271size_t find_last_slash(
const string &path)
273 for (
size_t i = 0; i < path.size(); ++i) {
274 size_t index = path.size() - 1 - i;
276 if (path[index] ==
DIR_SEP || path[index] == DIR_SEP_ALT)
291 static bool env_init =
false;
292 static char *env_shader_path;
293 static char *env_source_path;
295 env_shader_path = getenv(
"CYCLES_SHADER_PATH");
297 env_source_path = getenv(
"CYCLES_KERNEL_PATH");
300 if (env_shader_path !=
NULL && sub ==
"shader") {
301 return env_shader_path;
303 else if (env_source_path !=
NULL && sub ==
"source") {
304 return env_source_path;
309#if defined(__linux__) || defined(__APPLE__)
310static string path_xdg_cache_get()
312 const char *home = getenv(
"XDG_CACHE_HOME");
317 home = getenv(
"HOME");
319 home = getpwuid(getuid())->pw_dir;
321 return path_join(
string(home),
".cache");
326void path_init(
const string &path,
const string &user_path)
335 OIIO::Filesystem::exists(path);
342 if (special !=
NULL) {
364#if defined(__linux__) || defined(__APPLE__)
376#if defined(__linux__) || defined(__APPLE__)
377string path_xdg_home_get(
const string &sub =
"");
382 size_t index = find_last_slash(path);
383 if (index != string::npos) {
386 if (index == 0 && path.size() == 1) {
390 if (index == path.size() - 1) {
398 return path.substr(index + 1, path.size() - index - 1);
405 size_t index = find_last_slash(path);
406 if (index != string::npos) {
408 if (index == 0 && path.size() > 1) {
412 return path.substr(0, index);
419 if (dir.size() == 0) {
422 if (file.size() == 0) {
429 if (result[result.size() - 1] !=
DIR_SEP && result[result.size() - 1] != DIR_SEP_ALT &&
430 file[0] !=
DIR_SEP && file[0] != DIR_SEP_ALT)
441 string result = path;
449# ifdef HAVE_SHLWAPI_H
450 return PathIsRelative(path.c_str());
452 if (path.size() >= 3) {
453 return !(((path[0] >=
'a' && path[0] <=
'z') || (path[0] >=
'A' && path[0] <=
'Z')) &&
454 path[1] ==
':' && path[2] ==
DIR_SEP);
459 if (path.size() == 0) {
468static string path_unc_add_slash_to_share(
const string &path)
470 size_t slash_after_server = path.find(
DIR_SEP, 2);
471 if (slash_after_server != string::npos) {
472 size_t slash_after_share = path.find(
DIR_SEP, slash_after_server + 1);
473 if (slash_after_share == string::npos) {
484static string path_unc_to_short(
const string &path)
486 size_t len = path.size();
487 if ((
len > 3) && (path[0] ==
DIR_SEP) && (path[1] ==
DIR_SEP) && (path[2] ==
'?') &&
488 ((path[3] ==
DIR_SEP) || (path[3] == DIR_SEP_ALT)))
490 if ((
len > 5) && (path[5] ==
':')) {
491 return path.substr(4,
len - 4);
493 else if ((
len > 7) && (path.substr(4, 3) ==
"UNC") &&
494 ((path[7] ==
DIR_SEP) || (path[7] == DIR_SEP_ALT)))
496 return "\\\\" + path.substr(8,
len - 8);
502static string path_cleanup_unc(
const string &path)
504 string result = path_unc_to_short(path);
505 if (path.size() > 2) {
508 return path_unc_add_slash_to_share(result);
515static string path_make_compatible(
const string &path)
517 string result = path;
519 if (result.size() > 3 && result[result.size() - 1] ==
DIR_SEP) {
520 result.resize(result.size() - 1);
523 if ((path.size() >= 3) && (path[0] ==
DIR_SEP) && (path[1] ==
DIR_SEP)) {
524 result = path_cleanup_unc(result);
527 if (result.size() == 2 && result[1] ==
':') {
533static int path_wstat(
const wstring &path_wc,
path_stat_t *st)
535# if defined(_MSC_VER) || defined(__MINGW64__)
536 return _wstat64(path_wc.c_str(), st);
537# elif defined(__MINGW32__)
538 return _wstati64(path_wc.c_str(), st);
540 return _wstat(path_wc.c_str(), st);
546 wstring path_wc = string_to_wstring(path);
547 return path_wstat(path_wc, st);
552 return stat(path.c_str(), st);
568 string fixed_path = path_make_compatible(path);
569 wstring path_wc = string_to_wstring(fixed_path);
571 if (path_wstat(path_wc, &st) != 0) {
574 return st.st_mode != 0;
577 if (stat(path.c_str(), &st) != 0) {
580 return st.st_mode != 0;
596 directory_iterator it(dir), it_end;
598 for (; it != it_end; ++it) {
603 string filepath = it->path();
605 hash.append((
const uint8_t *)filepath.c_str(), filepath.size());
606 hash.append_file(filepath);
619 return hash.get_hex();
634 if (parent.size() > 0 && parent != path) {
641 wstring path_wc = string_to_wstring(path);
642 return _wmkdir(path_wc.c_str()) == 0;
644 return mkdir(path.c_str(), 0777) == 0;
665 if (binary.size() > 0) {
666 fwrite(&binary[0],
sizeof(
uint8_t), binary.size(), f);
677 std::copy(text.begin(), text.end(), binary.begin());
694 if (binary.size() == 0) {
699 if (fread(&binary[0],
sizeof(
uint8_t), binary.size(), f) != binary.size()) {
720 const size_t full_size = ZSTD_getFrameContentSize(compressed.data(), compressed.size());
722 if (full_size == ZSTD_CONTENTSIZE_ERROR) {
726 if (full_size == ZSTD_CONTENTSIZE_UNKNOWN) {
732 binary.resize(full_size);
734 size_t err = ZSTD_decompress(binary.data(), binary.size(), compressed.data(), compressed.size());
736 return ZSTD_isError(err) == 0;
747 const char *
str = (
const char *)&binary[0];
748 size_t size = binary.size();
749 text = string(
str, size);
762 const char *
str = (
const char *)&binary[0];
763 size_t size = binary.size();
764 text = string(
str, size);
780 return remove(path.c_str()) == 0;
794 const string &source_filepath,
799 const size_t line_number)
801 string unescaped_path = path;
805 const size_t base_len =
state.base.length();
806 unescaped_path = base_file +
807 unescaped_path.substr(base_len, unescaped_path.length() - base_len);
810 const size_t length = unescaped_path.length();
811 string escaped_path =
"";
812 for (
size_t i = 0; i <
length; ++i) {
813 const char ch = unescaped_path[i];
814 if (strchr(
"\"\'\?\\", ch) !=
nullptr) {
815 escaped_path +=
"\\";
819 return "#line " + std::to_string(line_number) +
'"' + escaped_path +
'"';
823 const string &source_filepath,
824 const size_t line_number,
827 string result = preprocessor_line;
829 string rest_of_line =
string_strip(preprocessor_line.substr(1));
831 if (0 == strncmp(rest_of_line.c_str(),
"include", 7)) {
833 if (rest_of_line[0] ==
'"') {
834 const size_t n_start = 1;
835 const size_t n_end = rest_of_line.find(
"\"", n_start);
836 const string filename = rest_of_line.substr(n_start, n_end - n_start);
860 const string &source_filepath,
863 const string *psource = &_source;
866 auto pragma_once = _source.find(
"#pragma once");
867 if (pragma_once != string::npos) {
868 if (
state->pragma_onced.find(source_filepath) !=
state->pragma_onced.end()) {
871 state->pragma_onced.insert(source_filepath);
875 source_new = _source;
876 memcpy(source_new.data() + pragma_once,
"//pr", 4);
877 psource = &source_new;
883 SourceReplaceState::ProcessedMapping::iterator replaced_file =
state->processed_files.find(
885 if (replaced_file !=
state->processed_files.end()) {
886 return replaced_file->second;
889 const string &source = *psource;
893 const size_t source_length = source.length();
896 size_t line_number = 0, column_number = 1;
901 size_t token_start = 0, token_length = 0;
908 bool inside_preprocessor =
false;
909 string preprocessor_line =
"";
911 while (index < source_length) {
912 char ch = source[index];
915 if (inside_preprocessor) {
917 preprocessor_line, source_filepath, line_number,
state);
919 if (!block.empty()) {
926 inside_preprocessor =
false;
927 preprocessor_line =
"";
932 else if (ch ==
'#' && column_number == 1 && !inside_preprocessor) {
934 if (token_length != 0) {
935 result.append(source, token_start, token_length);
939 inside_preprocessor =
true;
942 if (inside_preprocessor) {
943 preprocessor_line += ch;
954 if (token_length != 0) {
955 result.append(source, token_start, token_length);
957 if (inside_preprocessor) {
959 preprocessor_line, source_filepath, line_number,
state);
976 wstring path_wc = string_to_wstring(path);
977 wstring mode_wc = string_to_wstring(mode);
978 return _wfopen(path_wc.c_str(), mode_wc.c_str());
980 return fopen(path.c_str(), mode.c_str());
988 std::time_t current_time = std::time(
nullptr);
989 OIIO::Filesystem::last_write_time(path, current_time);
1004 const size_t max_old_kernel_of_same_type)
1014 directory_iterator it(dir), it_end;
1017 for (; it != it_end; ++it) {
1018 const string &path = it->path();
1019 if (path == new_path) {
1023 std::time_t last_time = OIIO::Filesystem::last_write_time(path);
1024 same_kernel_types.emplace_back(last_time, path);
1027 if (same_kernel_types.size() > max_old_kernel_of_same_type) {
1028 sort(same_kernel_types.begin(), same_kernel_types.end());
1030 for (
int i = 0; i < same_kernel_types.size() - max_old_kernel_of_same_type; i++) {
void BLI_kdtree_nd_ free(KDTree *tree)
static DBVT_INLINE btDbvtNode * sort(btDbvtNode *n, btDbvtNode *&r)
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
#define CCL_NAMESPACE_END
GPUAttachmentType & operator++(GPUAttachmentType &a)
ccl_device_inline bool operator!=(const float2 a, const float2 b)
size_t path_file_size(const string &path)
bool path_read_compressed_binary(const string &path, vector< uint8_t > &binary)
static string path_source_replace_includes_recursive(const string &source, const string &source_filepath, SourceReplaceState *state)
static string cached_user_path
string path_user_get(const string &sub)
string path_cache_get(const string &sub)
bool path_is_directory(const string &path)
FILE * path_fopen(const string &path, const string &mode)
string path_dirname(const string &path)
string path_source_replace_includes(const string &source, const string &path)
static string path_source_handle_preprocessor(const string &preprocessor_line, const string &source_filepath, const size_t line_number, SourceReplaceState *state)
typedefCCL_NAMESPACE_BEGIN struct stat path_stat_t
static int path_stat(const string &path, path_stat_t *st)
string path_get(const string &sub)
string path_files_md5_hash(const string &dir)
bool path_is_relative(const string &path)
uint64_t path_modified_time(const string &path)
string path_join(const string &dir, const string &file)
static void path_cache_kernel_mark_used(const string &path)
bool path_exists(const string &path)
static string line_directive(const SourceReplaceState &state, const string &path, const size_t line_number)
bool path_cache_kernel_exists_and_mark_used(const string &path)
static bool create_directories_recursivey(const string &path)
string path_escape(const string &path)
void path_cache_kernel_mark_added_and_clear_old(const string &new_path, const size_t max_old_kernel_of_same_type)
bool path_write_binary(const string &path, const vector< uint8_t > &binary)
void path_create_directories(const string &filepath)
bool path_write_text(const string &path, string &text)
static void path_files_md5_hash_recursive(MD5Hash &hash, const string &dir)
bool path_read_text(const string &path, string &text)
static string cached_xdg_cache_path
bool path_read_compressed_text(const string &path, string &text)
string path_filename(const string &path)
static char * path_specials(const string &sub)
static string cached_path
bool path_remove(const string &path)
void path_init(const string &path, const string &user_path)
bool path_read_binary(const string &path, vector< uint8_t > &binary)
unsigned __int64 uint64_t
string string_strip(const string &s)
bool string_startswith(const string_view s, const string_view start)
void string_replace(string &haystack, const string &needle, const string &other)
bool string_endswith(const string_view s, const string_view end)
ProcessedMapping processed_files
set< string > pragma_onced
map< string, string > ProcessedMapping