RigsofRods
Soft-body Physics Simulation
PlatformUtils.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2005-2012 Pierre-Michel Ricordel
4  Copyright 2007-2012 Thomas Fischer
5  Copyright 2013-2020 Petr Ohlidal
6 
7  For more information, see http://www.rigsofrods.org/
8 
9  Rigs of Rods is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License version 3, as
11  published by the Free Software Foundation.
12 
13  Rigs of Rods is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
25 
26 
27 #include "PlatformUtils.h"
28 #include "Application.h"
29 
30 #ifdef _MSC_VER
31  #include <Windows.h>
32  #include <shlobj.h> // SHGetFolderPathW()
33  #include <shellapi.h> // ShellExecute()
34 #else
35  #include <sys/types.h>
36  #include <sys/stat.h>
37  #include <unistd.h> // readlink()
38 #endif
39 
40 #include <OgrePlatform.h>
41 #include <OgreFileSystem.h>
42 #include <string>
43 
44 namespace RoR {
45 
46 #ifdef _MSC_VER
47 
48 // -------------------------- File/path utils for MS Windows --------------------------
49 // Based on research in https://github.com/only-a-ptr/filepaths4rigs
50 
51 char PATH_SLASH = '\\';
52 
53 std::wstring MSW_Utf8ToWchar(const char* path)
54 {
55  if( path == nullptr || path[0] == 0 )
56  {
57  RoR::Log("[RoR] Internal error: MSW_Utf8ToWchar() received empty input");
58  return std::wstring();
59  }
60 
61  int size_needed = MultiByteToWideChar(CP_UTF8, 0, &path[0], -1, NULL, 0); // Doc: https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072(v=vs.85).aspx
62  std::wstring out_wstr( size_needed, 0 );
63  int raw_result = MultiByteToWideChar(CP_UTF8, 0, &path[0], -1, &out_wstr[0], size_needed);
64  if (raw_result <= 0)
65  {
66  RoR::LogFormat("[RoR] Internal error: MSW_Utf8ToWchar() could not convert UTF-8 to UTF-16; MultiByteToWideChar() returned %d", raw_result);
67  return std::wstring();
68  }
69  return out_wstr;
70 }
71 
72 DWORD MSW_GetFileAttrs(const char* path)
73 {
74  if (path == nullptr || path[0] == 0)
75  {
76  return INVALID_FILE_ATTRIBUTES;
77  }
78 
79  std::wstring wpath = MSW_Utf8ToWchar(path);
80  // Function reference: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364944(v=vs.85).aspx
81  // File attribute constants: https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx
82  return GetFileAttributesW(wpath.c_str());
83 }
84 
85 std::string MSW_WcharToUtf8(const wchar_t* wstr) // wstr _must_ be NUL-terminated!
86 {
87  if( wstr == nullptr || wstr[0] == 0 )
88  {
89  RoR::Log("[RoR] Internal error: MSW_WcharToUtf8() received empty input");
90  return std::string();
91  }
92 
93  const int dst_size = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], -1, nullptr, 0, nullptr, nullptr);
94  std::string dst(dst_size, 0); // Construct by length and initial value
95  int raw_result = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], -1, &dst[0], dst_size, nullptr, nullptr);
96  if (raw_result <= 0)
97  {
98  RoR::LogFormat("[RoR] Internal error: MSW_WcharToUtf8() could not convert UTF-16 to UTF-8; WideCharToMultiByte() returned %d", raw_result);
99  return std::string();
100  }
101  return dst;
102 }
103 
104 bool FileExists(const char *path)
105 {
106  DWORD file_attrs = MSW_GetFileAttrs(path);
107  return (file_attrs != INVALID_FILE_ATTRIBUTES && ! (file_attrs & FILE_ATTRIBUTE_DIRECTORY));
108 }
109 
110 bool FolderExists(const char* path)
111 {
112  DWORD file_attrs = MSW_GetFileAttrs(path);
113  return (file_attrs != INVALID_FILE_ATTRIBUTES && (file_attrs & FILE_ATTRIBUTE_DIRECTORY));
114 }
115 
116 void CreateFolder(const char* path)
117 {
118  if (!FolderExists(path))
119  {
120  std::wstring wpath = MSW_Utf8ToWchar(path);
121  CreateDirectoryW(wpath.c_str(), nullptr);
122  }
123 }
124 
125 std::string GetUserHomeDirectory()
126 {
127  std::wstring out_wstr(MAX_PATH, 0); // Length limit imposed by the function, see https://msdn.microsoft.com/en-us/library/windows/desktop/bb762181(v=vs.85).aspx
128  HRESULT hres = SHGetFolderPathW(nullptr, CSIDL_PERSONAL, nullptr, SHGFP_TYPE_CURRENT, &out_wstr[0]);
129  if (hres != S_OK)
130  {
131  RoR::LogFormat("[RoR] Internal error: GetUserHomeDirectory() failed; SHGetFolderPathW() returned %ld", static_cast<long>(hres));
132  return std::string();
133  }
134 
135  return MSW_WcharToUtf8(out_wstr.c_str());
136 }
137 
138 std::string GetExecutablePath()
139 {
140  const int BUF_SIZE = 500;
141  std::wstring out_wstr(BUF_SIZE, 0);
142  DWORD res = GetModuleFileNameW(nullptr, &out_wstr[0], BUF_SIZE);
143  if (res <= 0)
144  {
145  RoR::LogFormat("[RoR] Internal error: GetExecutablePath() failed; GetModuleFileNameW() returned %d", static_cast<int>(res));
146  return std::string();
147  }
148 
149  return MSW_WcharToUtf8(out_wstr.c_str());
150 }
151 
152 void OpenUrlInDefaultBrowser(std::string const& url)
153 {
154  ::ShellExecute(0, 0, url.c_str(), 0, 0 , SW_SHOW );
155 }
156 
157 #else
158 
159 // -------------------------- File/path utils for Linux/*nix --------------------------
160 
161 char PATH_SLASH = '/';
162 
163 bool FileExists(const char *path)
164 {
165  struct stat st;
166  return (stat(path, &st) == 0);
167 }
168 
169 bool FolderExists(const char* path)
170 {
171  struct stat st;
172  return (stat(path, &st) == 0);
173 }
174 
175 void CreateFolder(const char* path)
176 {
177  mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
178 }
179 
180 std::string GetUserHomeDirectory()
181 {
182  return getenv("HOME");
183 }
184 
185 std::string GetExecutablePath()
186 {
187  const int BUF_SIZE = 500;
188  std::string buf_str(BUF_SIZE, 0);
189  // Linux or POSIX assumed; http://stackoverflow.com/a/625523
190  if (readlink("/proc/self/exe", &buf_str[0], BUF_SIZE-1) == -1)
191  {
192  RoR::LogFormat("[RoR] Internal error: GetExecutablePath() failed; readlink() sets errno to %d", static_cast<int>(errno));
193  return std::string();
194  }
195 
196  return std::move(buf_str);
197 }
198 
199 void OpenUrlInDefaultBrowser(std::string const& url)
200 {
201  std::string buf = "xdg-open " + url;
202  ::system(buf.c_str());
203 }
204 
205 #endif // _MSC_VER
206 
207 // -------------------------- File/path common utils --------------------------
208 
209 std::string GetParentDirectory(const char* src_buff)
210 {
211  const char* start = src_buff;
212  size_t count = strlen(src_buff);
213  // Trim trailing separator(s)
214  for (;;)
215  {
216  if (count == 0) { return std::string(); }
217  if (start[count - 1] != PATH_SLASH) { break; }
218  --count;
219  }
220  // Remove last path entry
221  for (;;)
222  {
223  if (count == 0) { return std::string(); }
224  if (start[count - 1] == PATH_SLASH) {break; }
225  --count;
226  }
227  // Trim rear separator(s)
228  for (;;)
229  {
230  if (count == 0) { return std::string(); }
231  if (start[count - 1] != PATH_SLASH) { break; }
232  --count;
233  }
234 
235  return std::string(start, count);
236 }
237 
238 std::time_t GetFileLastModifiedTime(std::string const & path)
239 {
240  Ogre::FileSystemArchiveFactory factory;
241  Ogre::Archive* fs_archive = factory.createInstance(path, /*readOnly*/true);
242  std::time_t time = fs_archive->getModifiedTime(path);
243  factory.destroyInstance(fs_archive);
244  return time;
245 }
246 } // namespace RoR
RoR::OpenUrlInDefaultBrowser
void OpenUrlInDefaultBrowser(std::string const &url)
Definition: PlatformUtils.cpp:199
RoR::LogFormat
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
Definition: Application.cpp:424
RoR::FolderExists
bool FolderExists(const char *path)
Path must be UTF-8 encoded.
Definition: PlatformUtils.cpp:169
RoR::PATH_SLASH
char PATH_SLASH
Definition: PlatformUtils.cpp:161
RoR::CreateFolder
void CreateFolder(const char *path)
Path must be UTF-8 encoded.
Definition: PlatformUtils.cpp:175
PlatformUtils.h
Platform-specific utilities. We use narrow UTF-8 encoded strings as paths. Inspired by http://utf8eve...
RoR::GetUserHomeDirectory
std::string GetUserHomeDirectory()
Returns UTF-8 path or empty string on error.
Definition: PlatformUtils.cpp:180
Application.h
Central state/object manager and communications hub.
RoR::GetFileLastModifiedTime
std::time_t GetFileLastModifiedTime(std::string const &path)
Definition: PlatformUtils.cpp:238
RoR::GetExecutablePath
std::string GetExecutablePath()
Returns UTF-8 path or empty string on error.
Definition: PlatformUtils.cpp:185
RoR::GetParentDirectory
std::string GetParentDirectory(const char *src_buff)
Returns UTF-8 path without trailing slash.
Definition: PlatformUtils.cpp:209
RoR
Definition: AppContext.h:36
RoR::Log
void Log(const char *msg)
The ultimate, application-wide logging function. Adds a line (any length) in 'RoR....
Definition: Application.cpp:419
RoR::FileExists
bool FileExists(const char *path)
Path must be UTF-8 encoded.
Definition: PlatformUtils.cpp:163