13#include <OpenImageIO/filesystem.h>
14#include <OpenImageIO/strutil.h>
15#include <OpenImageIO/sysutil.h>
25# define DIR_SEP_ALT '/'
31# 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) {}
174 void current_entry_set(
const struct dirent *entry)
181 const struct dirent *entry_ =
nullptr;
184 directory_iterator() : path_info_(
""), name_list_(
nullptr), 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_,
nullptr, 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_ ==
nullptr) {
256 for (
int i = 0;
i < num_entries_; ++
i) {
259 free((
void *)name_list_);
260 name_list_ =
nullptr;
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 const 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 !=
nullptr && sub ==
"shader") {
301 return env_shader_path;
303 if (env_source_path !=
nullptr && 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");
316 home = getenv(
"HOME");
317 if (home ==
nullptr) {
318 home = getpwuid(getuid())->pw_dir;
320 return path_join(
string(home),
".cache");
324void path_init(
const string &path,
const string &user_path)
333 OIIO::Filesystem::exists(path);
340 if (special !=
nullptr) {
362#if defined(__linux__) || defined(__APPLE__)
374#if defined(__linux__) || defined(__APPLE__)
375string path_xdg_home_get(
const string &sub =
"");
380 const size_t index = find_last_slash(path);
381 if (index != string::npos) {
384 if (index == 0 && path.size() == 1) {
388 if (index == path.size() - 1) {
396 return path.substr(index + 1, path.size() - index - 1);
403 const size_t index = find_last_slash(path);
404 if (index != string::npos) {
406 if (index == 0 && path.size() > 1) {
410 return path.substr(0, index);
428 file[0] !=
DIR_SEP && file[0] != DIR_SEP_ALT)
447# ifdef HAVE_SHLWAPI_H
448 return PathIsRelative(path.c_str());
450 if (path.size() >= 3) {
451 return !(((path[0] >=
'a' && path[0] <=
'z') || (path[0] >=
'A' && path[0] <=
'Z')) &&
452 path[1] ==
':' && path[2] ==
DIR_SEP);
466static string path_unc_add_slash_to_share(
const string &path)
468 size_t slash_after_server = path.find(
DIR_SEP, 2);
469 if (slash_after_server != string::npos) {
470 size_t slash_after_share = path.find(
DIR_SEP, slash_after_server + 1);
471 if (slash_after_share == string::npos) {
482static string path_unc_to_short(
const string &path)
484 size_t len = path.size();
485 if ((
len > 3) && (path[0] ==
DIR_SEP) && (path[1] ==
DIR_SEP) && (path[2] ==
'?') &&
486 ((path[3] ==
DIR_SEP) || (path[3] == DIR_SEP_ALT)))
488 if ((
len > 5) && (path[5] ==
':')) {
489 return path.substr(4,
len - 4);
491 else if ((
len > 7) && (path.substr(4, 3) ==
"UNC") &&
492 ((path[7] ==
DIR_SEP) || (path[7] == DIR_SEP_ALT)))
494 return "\\\\" + path.substr(8,
len - 8);
500static string path_cleanup_unc(
const string &path)
502 string result = path_unc_to_short(path);
503 if (path.size() > 2) {
506 return path_unc_add_slash_to_share(
result);
513static string path_make_compatible(
const string &path)
521 if ((path.size() >= 3) && (path[0] ==
DIR_SEP) && (path[1] ==
DIR_SEP)) {
531static int path_wstat(
const wstring &path_wc,
path_stat_t *st)
533# if defined(_MSC_VER) || defined(__MINGW64__)
534 return _wstat64(path_wc.c_str(), st);
535# elif defined(__MINGW32__)
536 return _wstati64(path_wc.c_str(), st);
538 return _wstat(path_wc.c_str(), st);
544 wstring path_wc = string_to_wstring(path);
545 return path_wstat(path_wc, st);
550 return stat(path.c_str(), st);
566 string fixed_path = path_make_compatible(path);
567 wstring path_wc = string_to_wstring(fixed_path);
569 if (path_wstat(path_wc, &st) != 0) {
572 return st.st_mode != 0;
575 if (stat(path.c_str(), &st) != 0) {
578 return st.st_mode != 0;
594 directory_iterator it(dir);
595 const directory_iterator it_end;
597 for (; it != it_end; ++it) {
602 const string filepath = it->path();
604 hash.append((
const uint8_t *)filepath.c_str(), filepath.size());
605 hash.append_file(filepath);
618 return hash.get_hex();
629 if (!parent.empty() && parent != path) {
636 wstring path_wc = string_to_wstring(path);
637 _wmkdir(path_wc.c_str());
639 mkdir(path.c_str(), 0777);
664 if (!binary.empty()) {
665 fwrite(binary.data(),
sizeof(uint8_t), binary.size(), f);
676 std::copy(text.begin(), text.end(), binary.begin());
693 if (binary.empty()) {
698 if (fread(binary.data(),
sizeof(uint8_t), binary.size(), f) != binary.size()) {
719 const size_t full_size = ZSTD_getFrameContentSize(compressed.data(), compressed.size());
721 if (full_size == ZSTD_CONTENTSIZE_ERROR) {
725 if (full_size == ZSTD_CONTENTSIZE_UNKNOWN) {
731 binary.resize(full_size);
733 const size_t err = ZSTD_decompress(
734 binary.data(), binary.size(), compressed.data(), compressed.size());
736 return ZSTD_isError(err) == 0;
747 const char *
str = (
const char *)binary.data();
748 const size_t size = binary.size();
762 const char *
str = (
const char *)binary.data();
763 const size_t size = binary.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();
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 const 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;
897 size_t column_number = 1;
902 size_t token_start = 0;
903 size_t token_length = 0;
910 bool inside_preprocessor =
false;
911 string preprocessor_line;
913 while (index < source_length) {
914 const char ch = source[index];
917 if (inside_preprocessor) {
919 preprocessor_line, source_filepath, line_number,
state);
921 if (!block.empty()) {
928 inside_preprocessor =
false;
929 preprocessor_line =
"";
934 else if (ch ==
'#' && column_number == 1 && !inside_preprocessor) {
936 if (token_length != 0) {
937 result.append(source, token_start, token_length);
941 inside_preprocessor =
true;
944 if (inside_preprocessor) {
945 preprocessor_line += ch;
956 if (token_length != 0) {
957 result.append(source, token_start, token_length);
959 if (inside_preprocessor) {
961 preprocessor_line, source_filepath, line_number,
state);
978 wstring path_wc = string_to_wstring(path);
979 wstring mode_wc = string_to_wstring(mode);
980 return _wfopen(path_wc.c_str(), mode_wc.c_str());
982 return fopen(path.c_str(), mode.c_str());
990 const std::time_t current_time = std::time(
nullptr);
991 OIIO::Filesystem::last_write_time(path, current_time);
1004 const size_t max_old_kernel_of_same_type)
1014 directory_iterator it(dir);
1015 const directory_iterator it_end;
1018 for (; it != it_end; ++it) {
1019 const string &path = it->path();
1020 if (path == new_path) {
1024 const std::time_t last_time = OIIO::Filesystem::last_write_time(path);
1025 same_kernel_types.emplace_back(last_time, path);
1028 if (same_kernel_types.size() > max_old_kernel_of_same_type) {
1029 sort(same_kernel_types.begin(), same_kernel_types.end());
1031 for (
int i = 0;
i < same_kernel_types.size() - max_old_kernel_of_same_type;
i++) {
void BLI_kdtree_nd_ free(KDTree *tree)
BLI_INLINE bool operator!=(const ListBase &a, const ListBase &b)
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
static DBVT_INLINE btDbvtNode * sort(btDbvtNode *n, btDbvtNode *&r)
#define CCL_NAMESPACE_END
GPUAttachmentType & operator++(GPUAttachmentType &a)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
float length(VecOp< float, D >) RET
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)
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)
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)
map< string, string > ProcessedMapping
ProcessedMapping processed_files
set< string > pragma_onced