Line data Source code
1 :
2 : /* Copyright (c) 2009-2016, Cedric Stalder <cedric.stalder@gmail.com>
3 : * Stefan Eilemann <eile@equalizergraphics.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #include "file.h"
20 :
21 : #include "debug.h"
22 : #include "memoryMap.h"
23 : #include "os.h"
24 :
25 : #include <boost/algorithm/string/predicate.hpp>
26 : #include <boost/filesystem/path.hpp>
27 : #include <boost/foreach.hpp>
28 : #include <boost/regex.hpp>
29 : #include <boost/tokenizer.hpp>
30 : #include <servus/serializable.h>
31 : #include <servus/uint128_t.h>
32 : #include <sys/stat.h>
33 : #ifdef _MSC_VER
34 : #include <direct.h>
35 : #include <windows.h>
36 : #define getcwd _getcwd
37 : #define MAXPATHLEN _MAX_PATH
38 : #elif __APPLE__
39 : #include <dirent.h>
40 : #include <mach-o/dyld.h>
41 : #else
42 : #include <dirent.h>
43 : #include <limits.h>
44 : #include <unistd.h>
45 : #endif
46 :
47 : namespace lunchbox
48 : {
49 1 : Strings searchDirectory(const std::string& directory,
50 : const std::string& pattern)
51 : {
52 1 : Strings files;
53 2 : const boost::regex regex(pattern);
54 :
55 : #ifdef _MSC_VER
56 : WIN32_FIND_DATA file;
57 : const std::string search = directory.empty() ? "*.*" : directory + "\\*.*";
58 : HANDLE hSearch = FindFirstFile(search.c_str(), &file);
59 :
60 : if (hSearch == INVALID_HANDLE_VALUE)
61 : {
62 : LBVERB << "Error finding the first file to match " << pattern << " in "
63 : << directory << std::endl;
64 : FindClose(hSearch);
65 : return files;
66 : }
67 :
68 : if (boost::regex_match(file.cFileName, regex))
69 : files.push_back(file.cFileName);
70 : while (FindNextFile(hSearch, &file))
71 : {
72 : if (boost::regex_match(file.cFileName, regex))
73 : files.push_back(file.cFileName);
74 : }
75 : FindClose(hSearch);
76 :
77 : #else
78 :
79 1 : DIR* dir = opendir(directory.c_str());
80 1 : if (!dir)
81 : {
82 0 : LBVERB << "Can't open directory " << directory << std::endl;
83 0 : return files;
84 : }
85 :
86 : struct dirent* entry;
87 :
88 71 : while ((entry = readdir(dir)) != 0)
89 : {
90 70 : const std::string candidate(entry->d_name);
91 35 : if (boost::regex_match(candidate, regex))
92 35 : files.push_back(entry->d_name);
93 : }
94 :
95 1 : closedir(dir);
96 : #endif
97 1 : return files;
98 : }
99 :
100 1 : std::string getFilename(const std::string& filename)
101 : {
102 1 : const size_t lastSeparator = filename.find_last_of("/\\");
103 1 : if (lastSeparator == std::string::npos)
104 0 : return filename;
105 : // lastSeparator + 1 may be at most equal to filename.size(), which is good
106 1 : return filename.substr(lastSeparator + 1);
107 : }
108 :
109 0 : std::string getDirname(const std::string& filename)
110 : {
111 0 : const size_t lastSeparator = filename.find_last_of("/\\");
112 0 : if (lastSeparator == std::string::npos)
113 0 : return "./"; // The final separator is always in the output.
114 : // The separator will be part of the output.
115 : // If lastSeparator == 0 (e.g. /file-or-dir) it will assume that the rest
116 : // of the path is a filename.
117 0 : return filename.substr(0, lastSeparator + 1);
118 : }
119 :
120 3 : std::string getExecutableDir()
121 : {
122 : // http://stackoverflow.com/questions/933850
123 : #ifdef _MSC_VER
124 : char result[MAX_PATH];
125 : const std::string execPath(result,
126 : GetModuleFileName(NULL, result, MAX_PATH));
127 : #elif __APPLE__
128 : char result[PATH_MAX + 1];
129 : uint32_t size = sizeof(result);
130 : if (_NSGetExecutablePath(result, &size) != 0)
131 : return std::string();
132 : const std::string execPath(result);
133 : #else
134 : char result[PATH_MAX];
135 3 : const ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
136 3 : if (count < 0)
137 : {
138 : // Not all UNIX have /proc/self/exe
139 0 : LBWARN << "Could not find absolute executable path" << std::endl;
140 0 : return "";
141 : }
142 6 : const std::string execPath(result, count);
143 : #endif
144 :
145 6 : const boost::filesystem::path path(execPath);
146 : #ifdef __APPLE__
147 : if (boost::algorithm::ends_with(path.parent_path().string(),
148 : "Contents/MacOS"))
149 : {
150 : return path.parent_path()
151 : .parent_path()
152 : .parent_path()
153 : .parent_path()
154 : .string();
155 : }
156 : #endif
157 3 : return path.parent_path().string();
158 : }
159 :
160 1 : std::string getWorkDir()
161 : {
162 : char cwd[MAXPATHLEN];
163 1 : return ::getcwd(cwd, MAXPATHLEN);
164 : }
165 :
166 1 : std::string getRootDir()
167 : {
168 2 : const std::string& exeDir = getExecutableDir();
169 1 : if (exeDir.empty())
170 0 : return exeDir;
171 :
172 2 : const boost::filesystem::path path(exeDir);
173 : #ifdef _MSC_VER
174 : const Strings buildTypes{"debug", "relwithdebinfo", "release",
175 : "minsizerel"};
176 : std::string buildType(path.stem().string());
177 : std::transform(buildType.begin(), buildType.end(), buildType.begin(),
178 : ::tolower);
179 : if (std::find(buildTypes.begin(), buildTypes.end(), buildType) !=
180 : buildTypes.end())
181 : {
182 : return path.parent_path().parent_path().string();
183 : }
184 : #endif
185 1 : return path.parent_path().string();
186 : }
187 :
188 0 : std::string getLibraryPath()
189 : {
190 0 : const std::string& exeDir = getExecutableDir();
191 0 : if (exeDir.empty())
192 0 : return exeDir;
193 :
194 : #ifdef _MSC_VER
195 : return exeDir;
196 : #elif __APPLE__
197 : const boost::filesystem::path path(exeDir);
198 :
199 : // foo.app/Contents/MacOS/foo
200 : if (boost::algorithm::ends_with(exeDir, ".app/Contents/MacOS"))
201 : return path.parent_path()
202 : .parent_path()
203 : .parent_path()
204 : .parent_path()
205 : .string() +
206 : "/lib";
207 : return path.parent_path().string() + "/lib";
208 : #else
209 0 : const boost::filesystem::path path(exeDir);
210 0 : return path.parent_path().string() + "/lib";
211 : #endif
212 : }
213 :
214 : #define STDSTRING(macro) std::string(STRINGIFY(macro))
215 : #define STRINGIFY(foo) #foo
216 :
217 0 : Strings getLibraryPaths()
218 : {
219 0 : Strings paths;
220 0 : const std::string& appPath = getLibraryPath();
221 0 : if (!appPath.empty())
222 0 : paths.push_back(appPath);
223 :
224 : #ifdef _MSC_VER
225 : paths.push_back(STDSTRING(CMAKE_INSTALL_PREFIX) + "/bin");
226 : const char* env = ::getenv("PATH");
227 : #elif __APPLE__
228 : paths.push_back(STDSTRING(CMAKE_INSTALL_PREFIX) + "/lib");
229 : const char* env = ::getenv("DYLD_LIBRARY_PATH");
230 : #else
231 0 : paths.push_back(STDSTRING(CMAKE_INSTALL_PREFIX) + "/lib");
232 0 : const char* env = ::getenv("LD_LIBRARY_PATH");
233 : #endif
234 :
235 0 : if (!env)
236 0 : return paths;
237 :
238 0 : const std::string envString(env);
239 : #ifdef _MSC_VER
240 : boost::char_separator<char> separator(";");
241 : #else
242 0 : boost::char_separator<char> separator(":");
243 : #endif
244 : const boost::tokenizer<boost::char_separator<char> > tokens(envString,
245 0 : separator);
246 0 : BOOST_FOREACH (const std::string& token, tokens)
247 0 : paths.push_back(token);
248 :
249 0 : return paths;
250 : }
251 :
252 0 : bool saveBinary(const servus::Serializable& object, const std::string& file)
253 : {
254 0 : const servus::Serializable::Data& data = object.toBinary();
255 0 : MemoryMap mmap(file, sizeof(uint128_t) + data.size);
256 0 : if (!mmap.getAddress())
257 0 : return false;
258 0 : const uint128_t& id = object.getTypeIdentifier();
259 0 : ::memcpy(mmap.getAddress(), &id, sizeof(id));
260 0 : ::memcpy(mmap.getAddress<uint8_t>() + sizeof(id), data.ptr.get(),
261 0 : data.size);
262 0 : return true;
263 : }
264 :
265 0 : bool loadBinary(servus::Serializable& object, const std::string& file)
266 : {
267 0 : const MemoryMap mmap(file);
268 0 : if (!mmap.getAddress() || mmap.getSize() < sizeof(uint128_t) ||
269 0 : *mmap.getAddress<uint128_t>() != object.getTypeIdentifier())
270 : {
271 0 : return false;
272 : }
273 :
274 0 : object.fromBinary(mmap.getAddress<uint8_t>() + sizeof(uint128_t),
275 0 : mmap.getSize() - sizeof(uint128_t));
276 0 : return true;
277 : }
278 :
279 0 : bool saveAscii(const servus::Serializable& object, const std::string& file)
280 : {
281 0 : const std::string& data = object.toJSON();
282 0 : MemoryMap mmap(file, data.length());
283 0 : if (!mmap.getAddress())
284 0 : return false;
285 0 : ::memcpy(mmap.getAddress(), &data[0], data.length());
286 0 : return true;
287 : }
288 :
289 0 : bool loadAscii(servus::Serializable& object, const std::string& file)
290 : {
291 0 : const MemoryMap mmap(file);
292 0 : if (!mmap.getAddress())
293 0 : return false;
294 0 : const uint8_t* ptr = mmap.getAddress<uint8_t>();
295 0 : object.fromJSON(std::string(ptr, ptr + mmap.getSize()));
296 0 : return true;
297 : }
298 75 : }
|