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 <servus/serializable.h>
26 : #include <servus/uint128_t.h>
27 : #include <boost/algorithm/string/predicate.hpp>
28 : #include <boost/filesystem/path.hpp>
29 : #include <boost/foreach.hpp>
30 : #include <boost/regex.hpp>
31 : #include <boost/tokenizer.hpp>
32 : #include <sys/stat.h>
33 : #ifdef _MSC_VER
34 : # include <windows.h>
35 : # include <direct.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, GetModuleFileName( NULL, result,
126 : 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
151 : path.parent_path().parent_path().parent_path().parent_path().string();
152 : }
153 : #endif
154 3 : return path.parent_path().string();
155 : }
156 :
157 1 : std::string getWorkDir()
158 : {
159 : char cwd[ MAXPATHLEN ];
160 1 : return ::getcwd( cwd, MAXPATHLEN );
161 : }
162 :
163 1 : std::string getRootDir()
164 : {
165 2 : const std::string& exeDir = getExecutableDir();
166 1 : if( exeDir.empty( ))
167 0 : return exeDir;
168 :
169 2 : const boost::filesystem::path path( exeDir );
170 : #ifdef _MSC_VER
171 : const Strings buildTypes { "debug", "relwithdebinfo", "release",
172 : "minsizerel" };
173 : std::string buildType( path.stem().string( ));
174 : std::transform( buildType.begin(), buildType.end(), buildType.begin(),
175 : ::tolower );
176 : if( std::find( buildTypes.begin(), buildTypes.end(),
177 : buildType ) != buildTypes.end( ))
178 : {
179 : return path.parent_path().parent_path().string();
180 : }
181 : #endif
182 1 : return path.parent_path().string();
183 : }
184 :
185 0 : std::string getLibraryPath()
186 : {
187 0 : const std::string& exeDir = getExecutableDir();
188 0 : if( exeDir.empty( ))
189 0 : return exeDir;
190 :
191 : #ifdef _MSC_VER
192 : return exeDir;
193 : #elif __APPLE__
194 : const boost::filesystem::path path( exeDir );
195 :
196 : // foo.app/Contents/MacOS/foo
197 : if( boost::algorithm::ends_with( exeDir, ".app/Contents/MacOS" ))
198 : return path.parent_path().parent_path().parent_path().parent_path().
199 : string() + "/lib";
200 : return path.parent_path().string() + "/lib";
201 : #else
202 0 : const boost::filesystem::path path( exeDir );
203 0 : return path.parent_path().string() + "/lib";
204 : #endif
205 : }
206 :
207 : #define STDSTRING( macro ) std::string( STRINGIFY( macro ))
208 : #define STRINGIFY( foo ) #foo
209 :
210 0 : Strings getLibraryPaths()
211 : {
212 0 : Strings paths;
213 0 : const std::string& appPath = getLibraryPath();
214 0 : if( !appPath.empty( ))
215 0 : paths.push_back( appPath );
216 :
217 : #ifdef _MSC_VER
218 : paths.push_back( STDSTRING( CMAKE_INSTALL_PREFIX ) + "/bin" );
219 : const char* env = ::getenv( "PATH" );
220 : #elif __APPLE__
221 : paths.push_back( STDSTRING( CMAKE_INSTALL_PREFIX ) + "/lib" );
222 : const char* env = ::getenv( "DYLD_LIBRARY_PATH" );
223 : #else
224 0 : paths.push_back( STDSTRING( CMAKE_INSTALL_PREFIX ) + "/lib" );
225 0 : const char* env = ::getenv( "LD_LIBRARY_PATH" );
226 : #endif
227 :
228 0 : if( !env )
229 0 : return paths;
230 :
231 0 : const std::string envString( env );
232 : #ifdef _MSC_VER
233 : boost::char_separator< char > separator(";");
234 : #else
235 0 : boost::char_separator< char > separator(":");
236 : #endif
237 : const boost::tokenizer< boost::char_separator< char > >
238 0 : tokens( envString, separator );
239 0 : BOOST_FOREACH( const std::string& token, tokens )
240 0 : paths.push_back( token );
241 :
242 0 : return paths;
243 : }
244 :
245 0 : bool saveBinary( const servus::Serializable& object, const std::string& file )
246 : {
247 0 : const servus::Serializable::Data& data = object.toBinary();
248 0 : MemoryMap mmap( file, sizeof( uint128_t ) + data.size );
249 0 : if( !mmap.getAddress( ))
250 0 : return false;
251 0 : const uint128_t& id = object.getTypeIdentifier();
252 0 : ::memcpy( mmap.getAddress(), &id, sizeof( id ));
253 0 : ::memcpy( mmap.getAddress< uint8_t >() + sizeof( id ),
254 0 : data.ptr.get(), data.size );
255 0 : return true;
256 : }
257 :
258 0 : bool loadBinary( servus::Serializable& object, const std::string& file )
259 : {
260 0 : const MemoryMap mmap( file );
261 0 : if( !mmap.getAddress() || mmap.getSize() < sizeof( uint128_t ) ||
262 0 : *mmap.getAddress< uint128_t >() != object.getTypeIdentifier( ))
263 : {
264 0 : return false;
265 : }
266 :
267 0 : object.fromBinary( mmap.getAddress< uint8_t >() + sizeof( uint128_t ),
268 0 : mmap.getSize() - sizeof( uint128_t ));
269 0 : return true;
270 : }
271 :
272 0 : bool saveAscii( const servus::Serializable& object, const std::string& file )
273 : {
274 0 : const std::string& data = object.toJSON();
275 0 : MemoryMap mmap( file, data.length( ));
276 0 : if( !mmap.getAddress( ))
277 0 : return false;
278 0 : ::memcpy( mmap.getAddress(), &data[0], data.length( ));
279 0 : return true;
280 : }
281 :
282 0 : bool loadAscii( servus::Serializable& object, const std::string& file )
283 : {
284 0 : const MemoryMap mmap( file );
285 0 : if( !mmap.getAddress( ))
286 0 : return false;
287 0 : const uint8_t* ptr = mmap.getAddress< uint8_t >();
288 0 : object.fromJSON( std::string( ptr, ptr + mmap.getSize( )));
289 0 : return true;
290 : }
291 :
292 :
293 72 : }
|