Spinning Topp Logo BlackTopp Studios
inc
resourceutilities.cpp
1 // © Copyright 2010 - 2016 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine 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 The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _resourceutilities_cpp
41 #define _resourceutilities_cpp
42 
43 #include "Resource/resourceutilities.h"
44 
45 #include "exception.h"
46 #include "stringtool.h"
47 
48 #include <dirent.h>
49 #ifdef MEZZ_WINDOWS
50  #include <Windows.h>
51  #include <Winuser.h>
52  #include <WinBase.h>
53  #include <Shlobj.h> // for getting system directories
54  // Below includes may not work on MSVC
55  #include <direct.h> // for _getcwd
56  #include <sys/stat.h>
57 #elif MEZZ_MACOSX
58  #include <CoreServices/CoreServices.h>
59  #include <unistd.h>//for sleep and getcwd
60  #include <errno.h>
61  #include <sys/stat.h>
62  #include <sys/types.h>
63  #include "pwd.h"
64  #include <mach-o/dyld.h> // for _NSGetExecutablePath
65 #else
66  #include <unistd.h> // for sleep and getcwd
67  #include <errno.h>
68  #include <sys/stat.h>
69  #include <sys/types.h>
70  #include <pwd.h>
71  #include <cstring> // for strerror
72 #endif
73 
74 #include <algorithm>
75 #include <cstdio>
76 
77 #ifdef CreateDirectory
78 #undef CreateDirectory
79 #endif
80 
81 #ifdef RemoveDirectory
82 #undef RemoveDirectory
83 #endif
84 
85 namespace
86 {
87  /// @brief ArgC as it was passed into Main.
88  /// @details This cannot be set statically, it must wait for main(int, char**) to
89  /// be initialized, then call the appropriate function to set this.
90  int ArgC;
91  /// @brief ArgC as it was passed into Main.
92  /// @details This cannot be set statically, it must wait for main(int, char**) to
93  /// be initialized, then call the appropriate function to set this.
94  char** ArgV;
95 }
96 
97 namespace Mezzanine
98 {
99  namespace Resource
100  {
101  ///////////////////////////////////////////////////////////////////////////////
102  // MainArg Utilities
103 
104  void CacheMainArgs(int ArgCount, char** ArgVars)
105  {
106  ArgC = ArgCount;
107  ArgV = ArgVars;
108  }
109 
110  ///////////////////////////////////////////////////////////////////////////////
111  // File Management
112 
113  /*Boole RemoveFile(const String& PathAndFile)
114  {
115  return ( remove( PathAndFile.c_str() ) == 0 );
116  }// */
117 
118  ///////////////////////////////////////////////////////////////////////////////
119  // Basic Directory Management
120 
121  Boole CreateDirectory(const String& DirectoryPath)
122  {
123  #ifdef MEZZ_WINDOWS
124  if( ::CreateDirectoryA(DirectoryPath.c_str(),NULL) < 0 ) {
125  if( ERROR_ALREADY_EXISTS == ::GetLastError() ) {
126  return false;
127  }
128  StringStream ExceptionStream;
129  ExceptionStream << "Unable to create directory. Error follows:" << std::endl;
130  if( ERROR_PATH_NOT_FOUND == ::GetLastError() ) {
131  ExceptionStream << "Path to requested directory does not exist.";
132  }else{
133  ExceptionStream << "Error Unknown. :(";
134  }
136  }
137  return true;
138  #else
139  if( ::mkdir(DirectoryPath.c_str(),0777) < 0 ) {
140  if( EEXIST == errno ) {
141  return false;
142  }
143  StringStream ExceptionStream;
144  ExceptionStream << "Unable to create directory. Error follows:" << std::endl;
145  ExceptionStream << std::strerror(errno);
147  }
148  return true;
149  #endif
150  }
151 
152  Boole CreateDirectoryPath(const String& DirectoryPath)
153  {
154  Boole Result = true;
155  StringVector FolderNames;
156  StringVector FolderVec = StringTools::Split(DirectoryPath,"/\\");
157  size_t StartIndex = 0;
158  String PathAttempt;
159  Char8 SysSlash = GetDirectorySeparator();
160  #ifdef MEZZ_WINDOWS
161  // For windows and windows like machines, see if the first entry is a drive, because attempting to make a drive is silly.
162  if( FolderVec.at(0).find(':') != String::npos ) {
163  PathAttempt.append( FolderVec.at(0) );
164  PathAttempt.append( 1, SysSlash );
165  StartIndex++;
166  }
167  #else
168  PathAttempt.append( 1, SysSlash );
169  #endif
170  for( size_t VecIndex = StartIndex ; VecIndex < FolderVec.size() ; ++VecIndex )
171  {
172  PathAttempt.append( FolderVec.at(VecIndex) );
173  PathAttempt.append( 1, SysSlash );
174  Result = CreateDirectory( PathAttempt );
175  }
176  return Result;
177  }
178 
179  Boole DoesDirectoryExist(const String& DirectoryPath)
180  {
181  struct stat st;
182  if( stat(DirectoryPath.c_str(),&st) == 0 ) {
183  return S_ISDIR(st.st_mode);
184  }/*else{
185  //MEZZ_EXCEPTION(ExceptionBase::IO_DIRECTORY_NOT_FOUND_EXCEPTION,"Unknown error getting directory information.");
186  return false;
187  }// */
188  return false;
189  }
190 
191  void RemoveDirectory(const String& DirectoryPath)
192  {
193  if( !rmdir(DirectoryPath.c_str()) ) {
194  return;
195  }else{
196  MEZZ_EXCEPTION(ExceptionBase::IO_DIRECTORY_NOT_FOUND_EXCEPTION,"Unknown error removing directory.");
197  }
198  }
199 
201  {
202  StringVector Results;
203  DIR *Directory;
204  struct dirent *DirEntry;
205  if( ( Directory = opendir( Dir.c_str() ) ) ) {
206  while( ( DirEntry = readdir(Directory) ) )
207  {
208  Results.push_back( DirEntry->d_name );
209  //DirEntry->d_type Later this can be modified to include the type of file entry it is, like a file, block device, directory, socket etc...
210  }
211 
212  closedir(Directory);
213  return Results;
214  }else{
215  MEZZ_EXCEPTION(ExceptionBase::IO_DIRECTORY_NOT_FOUND_EXCEPTION,String("Error listing directory contents"));
216  }
217  }
218 
219  ///////////////////////////////////////////////////////////////////////////////
220  // Path Utilities
221 
222  String DirName(const String& FileName)
223  {
224  Whole Last(FileName.find_last_of("\\/"));
225  if(FileName.npos == Last) {
226  return String();
227  }else{
228  if( Last<FileName.size() ) {
229  return FileName.substr(0,Last+1);
230  }else{
231  return FileName.substr(0,Last+1);
232  }
233  }
234  }
235 
236  String BaseName(const String& FileName)
237  {
238  Whole Last(FileName.find_last_of("\\/"));
239  if(FileName.npos == Last) {
240  return FileName;
241  }else{
242  if(Last<FileName.size()) {
243  return FileName.substr(Last+1,FileName.npos);
244  }else{
245  return String("");
246  }
247  }
248  }
249 
251  {
252  #ifdef MEZZ_WINDOWS
253  return '\\';
254  #else
255  return '/';
256  #endif
257  }
258 
260  {
261  #ifdef MEZZ_WINDOWS
262  return ';';
263  #else
264  return ':';
265  #endif
266  }
267 
268  String CombinePathAndFileName(const String& FilePath, const String& FileName)
269  {
270  String FullPath = FilePath;
272  if( !StringTools::EndsWith(FilePath,Separator,true) ) {
273  FullPath.append(Separator);
274  }
275  FullPath.append(FileName);
276  return FullPath;
277  }
278 
279  ///////////////////////////////////////////////////////////////////////////////
280  // System Path Utilities
281 
283  {
284  StringVector Results;
285  const Char8 Sep = GetPathSeparator();
286  String OneEntry;
287 
288  for( String::const_iterator Current = PATH.begin() ; PATH.end()!=Current ; ++Current )
289  {
290  if(Sep==*Current) {
291  Results.push_back(OneEntry);
292  OneEntry.clear();
293  }else{
294  OneEntry += *Current;
295  }
296  }
297  return Results;
298  }
299 
300  String Which(const String& ExecutableName)
301  {
302  StringVector PATH( GetSystemPATH() );
303 
304  for( StringVector::const_iterator Iter = PATH.begin() ; Iter!=PATH.end() ; ++Iter )
305  {
306  StringVector Entries( GetDirContents(*Iter) );
307  if( std::find(Entries.begin(),Entries.end(),ExecutableName) != Entries.end() ) {
308  return (*Iter) + GetDirectorySeparator();
309  }
310  }
311  return String();
312  }
313 
314  ///////////////////////////////////////////////////////////////////////////////
315  // Execution Directory Utilities
316 
318  {
319  return GetExecutableDir(ArgC,ArgV);
320  }
321 
322  String GetExecutableDir(int ArgCount, char** ArgVars)
323  {
324  String Results( GetExecutableDirFromArg(ArgCount,ArgVars) );
325  if( String(".") == Results || String("") == Results ) { // Means it might have valid exename
327  }else{
328  return Results;
329  }
330  }
331 
333  {
334  char Results[FILENAME_MAX];
335  #ifdef MEZZ_LINUX
336  MaxInt Length = ::readlink("/proc/self/exe", Results, sizeof(Results)-1);
337  if( Length != -1 ) {
338  Results[Length] = '\0';
339  return DirName(String(Results));
340  }else{
341  return "";
342  }
343  #endif
344  #ifdef MEZZ_WINDOWS
345  GetModuleFileName( NULL, Results, FILENAME_MAX );
346  return DirName(String(Results));
347  #endif
348  #ifdef MEZZ_MACOSX
349  uint32_t size = sizeof(Results);
350  if( _NSGetExecutablePath(Results, &size) == 0 ) {
351  return DirName(String(Results));
352  }else{
353  return "";
354  }
355  #endif
356  }
357 
359  {
361  }
362 
363  String GetExecutableDirFromArg(int ArgCount, char** ArgVars)
364  {
365  if(ArgCount>0) {
366  if(String("") == BaseName(ArgVars[0])) { // No command is clearly bogus, must bail
367  return "";
368  }
369 
370  String Results(DirName(ArgVars[0]));
371 
372  // strip ./ ../ .\ ..\ and
373  //String::iterator From=Results.begin();
374  //for(String::iterator Iter=Results.begin(); Iter!=Results.end();)
375  //{}
376 
377  if( String("") == Results || String("./") == Results || String(".\\") == Results) {// common cases of exe existing but dir is empty
378  return ".";
379  }
380 
381  if(String("")!=Results) { // and exe is empty.
382  return Results;
383  }
384  return String("");
385  }else{
386  return String("");
387  }
388  }
389 
390  ///////////////////////////////////////////////////////////////////////////////
391  // Working Directory Utilities
392 
393  void ChangeWorkingDirectory(const String& ChangeTo)
394  {
395  #ifdef MEZZ_WINDOWS
396  if(_chdir(ChangeTo.c_str()))
397  #else
398  if(chdir(ChangeTo.c_str()))
399  #endif
400  { MEZZ_EXCEPTION(ExceptionBase::IO_DIRECTORY_NOT_FOUND_EXCEPTION,String("Could not change to directory \"")+ChangeTo+"\" error: "+ToString(errno)); }
401  }
402 
404  {
405  char cCurrentPath[FILENAME_MAX];
406  // char cCurrentPath[MAXPATHLEN];
407  #ifdef MEZZ_WINDOWS
408  String Results (_getcwd(cCurrentPath,sizeof(cCurrentPath)));
409  #else
410  String Results (getcwd(cCurrentPath,sizeof(cCurrentPath)));
411  #endif
412  return Results;
413  }
414 
415  ///////////////////////////////////////////////////////////////////////////////
416  // Application Data Directory Utilities
417 
419  {
420  String LowerVar = PathVar;
421  StringTools::ToLowerCase(LowerVar);
422  if(LowerVar == "localappdata") return GetLocalAppDataDir();
423  else if(LowerVar == "shareableappdata") return GetShareableAppDataDir();
424  else if(LowerVar == "currentuserdata") return GetCurrentUserDataDir();
425  else if(LowerVar == "commonuserdata") return GetCommonUserDataDir();
426  else
427  {
428  MEZZ_EXCEPTION(ExceptionBase::PARAMETERS_EXCEPTION,"Attempting to retrieve unknown path variable: \"" + PathVar + "\".");
429  }
430  }
431 
433  {
434  #ifdef MEZZ_WINDOWS
435  TCHAR path_local_appdata[MAX_PATH];
436  if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, path_local_appdata))) {
437  return path_local_appdata;
438  }
439  #else
440  struct passwd* pw = getpwuid(getuid());
441  if(pw) {
442  return String(pw->pw_dir);
443  }else{
444  MEZZ_EXCEPTION(ExceptionBase::INVALID_STATE_EXCEPTION,"Could not get user information to retrieve app data directory.");
445  }
446 
447  // might be some useful MAC OS X code
448  /*#elif MEZZ_MACOSX
449  FSRef ref;
450  OSType folderType = kApplicationSupportFolderType;
451  char path[PATH_MAX];
452  FSFindFolder( kUserDomain, folderType, kCreateFolder, &ref );
453  FSRefMakePath( &ref, (UInt8*)&path, PATH_MAX );
454  return path;*/
455  #endif
456  return "";
457  }
458 
460  {
461  #ifdef MEZZ_WINDOWS
462  TCHAR path_appdata[MAX_PATH];
463  if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, path_appdata))) {
464  return path_appdata;
465  }
466  #else
467  struct passwd* pw = getpwuid(getuid());
468  if(pw) {
469  return String(pw->pw_dir);
470  }else{
471  MEZZ_EXCEPTION(ExceptionBase::INVALID_STATE_EXCEPTION,"Could not get user information to retrieve home directory.");
472  }
473  #endif
474  return "";
475  }
476 
478  {
479  #ifdef MEZZ_WINDOWS
480  TCHAR path_personal[MAX_PATH];
481  if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL, 0, path_personal))) {
482  return path_personal;
483  }
484  #else
485  struct passwd* pw = getpwuid(getuid());
486  if(pw) {
487  return String(pw->pw_dir);
488  }else{
489  MEZZ_EXCEPTION(ExceptionBase::INVALID_STATE_EXCEPTION,"Could not get user information to retrieve user data directory.");
490  }
491  #endif
492  return "";
493  }
494 
496  {
497  #ifdef MEZZ_WINDOWS
498  TCHAR path_common_personal[MAX_PATH];
499  if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS|CSIDL_FLAG_CREATE, NULL, 0, path_common_personal))) {
500  return path_common_personal;
501  }
502  #else
503  struct passwd* pw = getpwuid(getuid());
504  if(pw) {
505  return String(pw->pw_dir);
506  }else{
507  MEZZ_EXCEPTION(ExceptionBase::INVALID_STATE_EXCEPTION,"Could not get user information to retrieve common data directory.");
508  }
509  #endif
510  return "";
511  }
512  }//Resource
513 }//Mezzanine
514 
515 #endif
StringVector GetSystemPATH(const String &PATH)
Get the $PATH or PATH% split and order for easy checking of how the OS does it.
char ** ArgV
ArgC as it was passed into Main.
Definition: mezztest.cpp:70
std::vector< String > StringVector
This is a simple datatype for a vector container of strings.
Definition: datatypes.h:212
int ArgC
ArgC as it was passed into Main.
Definition: mezztest.cpp:62
bool Boole
Generally acts a single bit, true or false.
Definition: datatypes.h:173
String ToString(const T &Datum)
Converts whatever to a String as long as a streaming operator is available for it.
Definition: datatypes.h:242
String ResolveDataPathFromString(const String &PathVar)
Resolves a string describing one of the platform data paths to the actual path it is...
String GetExecutableDir()
Get the Path to the current executable, in a fast way if possible.
Char8 GetPathSeparator()
Get the character used to separate entries in the system PATH.
#define MEZZ_EXCEPTION(num, desc)
An easy way to throw exceptions with rich information.
Definition: exception.h:3048
Boole CreateDirectoryPath(const String &DirectoryPath)
Creates all directories that do not exist in the provided path.
String CombinePathAndFileName(const String &FilePath, const String &FileName)
Convenience method to verify the necessary system separator is present when concatenating.
String GetExecutableDirFromArg()
Uses the main parameters stored using "CacheMainArgs" to attempt determine executable directory...
Boole EndsWith(const String &Str, const String &Pattern, const Boole CaseSensitive)
Checks a String to see if it ends with a specific pattern.
Definition: stringtool.cpp:247
String GetLocalAppDataDir()
Gets the path to the directory intended for game and engine config data that is not meant to be share...
This implements the exception hiearchy for Mezzanine.
String GetShareableAppDataDir()
Gets the path to the directory intended for game and engine config data that is allowed to be shared...
std::stringstream StringStream
A Datatype used for streaming operations with strings.
Definition: datatypes.h:176
void ToLowerCase(String &Source)
Converts all upper case characters in a string to their respective lower case.
Definition: stringtool.cpp:193
StringVector GetDirContents(const String &Dir)
Get a Listing of the files and subdirectories in a directory.
void ChangeWorkingDirectory(const String &ChangeTo)
Change directory, to the directory indicated.
char Char8
A datatype to represent one character.
Definition: datatypes.h:169
String DirName(const String &FileName)
Get the directory portion of a string.
String Which(const String &ExecutableName)
Search the system path the same way most systems do to find an executable.
String GetWorkingDirectory()
Get the working directory as a Mezzanine::String.
String GetCommonUserDataDir()
Gets the path to the directory intended for game saves and user profile data for all users...
String GetExecutableDirFromSystem()
Used a system call to get the curent Directory the executable is in. This make an external system cal...
StringVector Split(const String &Source, const String &Delims, const Whole MaxSplits)
Splits a string into multiple substrings based on the specified delimiters.
Definition: stringtool.cpp:155
Boole CreateDirectory(const String &DirectoryPath)
Creates a single new directory.
Thrown when the available information should have worked but failed for unknown reasons.
Definition: exception.h:113
Char8 GetDirectorySeparator()
Get the character used to separate directories.
String BaseName(const String &FileName)
Get the filename portion of a string.
Thrown when parameters are checked at runtime and found invalid.
Definition: exception.h:108
long long MaxInt
A large integer type suitable for compile time math and long term microsecond time keeping...
Definition: datatypes.h:190
void RemoveDirectory(const String &DirectoryPath)
Remove an empty directory. Error this might throw a Mezzanine::IOException with details about why it ...
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
Definition: datatypes.h:151
void CacheMainArgs(int ArgCount, char **ArgVars)
Store the Main arguments for later use.
std::string String
A datatype used to a series of characters.
Definition: datatypes.h:159
Boole DoesDirectoryExist(const String &DirectoryPath)
Checks to see if the given path exists and if it is a folder. Error this might throw a Mezzanine::IOE...
String GetCurrentUserDataDir()
Gets the path to the directory intended for game saves and user profile data for the current user...
Thrown when a directory was expected to be there, but was not.
Definition: exception.h:82