Merged revision(s) 58452-58584 from trunk/blender into soc-2013-dingto.
[blender-staging.git] / intern / cycles / util / util_path.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "util_debug.h"
20 #include "util_md5.h"
21 #include "util_path.h"
22 #include "util_string.h"
23
24 #include <OpenImageIO/sysutil.h>
25 OIIO_NAMESPACE_USING
26
27 #include <stdio.h>
28
29 #include <boost/version.hpp>
30
31 #if (BOOST_VERSION < 104400)
32 #  define BOOST_FILESYSTEM_VERSION 2
33 #endif
34
35 #include <boost/filesystem.hpp> 
36 #include <boost/algorithm/string.hpp>
37
38 CCL_NAMESPACE_BEGIN
39
40 static string cached_path = "";
41 static string cached_user_path = "";
42
43 void path_init(const string& path, const string& user_path)
44 {
45         cached_path = path;
46         cached_user_path = user_path;
47 }
48
49 string path_get(const string& sub)
50 {
51         if(cached_path == "")
52                 cached_path = path_dirname(Sysutil::this_program_path());
53
54         return path_join(cached_path, sub);
55 }
56
57 string path_user_get(const string& sub)
58 {
59         if(cached_user_path == "")
60                 cached_user_path = path_dirname(Sysutil::this_program_path());
61
62         return path_join(cached_user_path, sub);
63 }
64
65 string path_filename(const string& path)
66 {
67 #if (BOOST_FILESYSTEM_VERSION == 2)
68         return boost::filesystem::path(path).filename();
69 #else
70         return boost::filesystem::path(path).filename().string();
71 #endif
72 }
73
74 string path_dirname(const string& path)
75 {
76         return boost::filesystem::path(path).parent_path().string();
77 }
78
79 string path_join(const string& dir, const string& file)
80 {
81         return (boost::filesystem::path(dir) / boost::filesystem::path(file)).string();
82 }
83
84 string path_escape(const string& path)
85 {
86         string result = path;
87         boost::replace_all(result, " ", "\\ ");
88         return result;
89 }
90
91 bool path_exists(const string& path)
92 {
93         return boost::filesystem::exists(path);
94 }
95
96 static void path_files_md5_hash_recursive(MD5Hash& hash, const string& dir)
97 {
98         if(boost::filesystem::exists(dir)) {
99                 boost::filesystem::directory_iterator it(dir), it_end;
100
101                 for(; it != it_end; it++) {
102                         if(boost::filesystem::is_directory(it->status())) {
103                                 path_files_md5_hash_recursive(hash, it->path().string());
104                         }
105                         else {
106                                 string filepath = it->path().string();
107
108                                 hash.append((const uint8_t*)filepath.c_str(), filepath.size());
109                                 hash.append_file(filepath);
110                         }
111                 }
112         }
113 }
114
115 string path_files_md5_hash(const string& dir)
116 {
117         /* computes md5 hash of all files in the directory */
118         MD5Hash hash;
119
120         path_files_md5_hash_recursive(hash, dir);
121
122         return hash.get_hex();
123 }
124
125 void path_create_directories(const string& path)
126 {
127         boost::filesystem::create_directories(path_dirname(path));
128 }
129
130 bool path_write_binary(const string& path, const vector<uint8_t>& binary)
131 {
132         path_create_directories(path);
133
134         /* write binary file from memory */
135         FILE *f = fopen(path.c_str(), "wb");
136
137         if(!f)
138                 return false;
139
140         if(binary.size() > 0)
141                 fwrite(&binary[0], sizeof(uint8_t), binary.size(), f);
142
143         fclose(f);
144
145         return true;
146 }
147
148 bool path_write_text(const string& path, string& text)
149 {
150         vector<uint8_t> binary(text.length(), 0);
151         std::copy(text.begin(), text.end(), binary.begin());
152
153         return path_write_binary(path, binary);
154 }
155
156 bool path_read_binary(const string& path, vector<uint8_t>& binary)
157 {
158         binary.resize(boost::filesystem::file_size(path));
159
160         /* read binary file into memory */
161         FILE *f = fopen(path.c_str(), "rb");
162
163         if(!f)
164                 return false;
165
166         if(binary.size() == 0) {
167                 fclose(f);
168                 return false;
169         }
170
171         if(fread(&binary[0], sizeof(uint8_t), binary.size(), f) != binary.size()) {
172                 fclose(f);
173                 return false;
174         }
175
176         fclose(f);
177
178         return true;
179 }
180
181 bool path_read_text(const string& path, string& text)
182 {
183         vector<uint8_t> binary;
184
185         if(!path_exists(path) || !path_read_binary(path, binary))
186                 return false;
187
188         const char *str = (const char*)&binary[0];
189         size_t size = binary.size();
190         text = string(str, size);
191
192         return true;
193 }
194
195 uint64_t path_modified_time(const string& path)
196 {
197         if(boost::filesystem::exists(path))
198                 return (uint64_t)boost::filesystem::last_write_time(path);
199         
200         return 0;
201 }
202
203 string path_source_replace_includes(const string& source_, const string& path)
204 {
205         /* our own little c preprocessor that replaces #includes with the file
206          * contents, to work around issue of opencl drivers not supporting
207          * include paths with spaces in them */
208         string source = source_;
209         const string include = "#include \"";
210         size_t n, pos = 0;
211
212         while((n = source.find(include, pos)) != string::npos) {
213                 size_t n_start = n + include.size();
214                 size_t n_end = source.find("\"", n_start);
215                 string filename = source.substr(n_start, n_end - n_start);
216
217                 string text, filepath = path_join(path, filename);
218
219                 if(path_read_text(filepath, text)) {
220                         text = path_source_replace_includes(text, path_dirname(filepath));
221                         source.replace(n, n_end + 1 - n, "\n" + text + "\n");
222                 }
223                 else
224                         pos = n_end;
225         }
226
227         return source;
228 }
229
230 CCL_NAMESPACE_END
231