Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
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
44namespace 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
51char PATH_SLASH = '\\';
52
53std::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
72DWORD 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
85std::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
104bool 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
110bool 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
116void 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
125std::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
138std::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
152void 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
161char PATH_SLASH = '/';
162
163bool FileExists(const char *path)
164{
165 struct stat st;
166 return (stat(path, &st) == 0);
167}
168
169bool FolderExists(const char* path)
170{
171 struct stat st;
172 return (stat(path, &st) == 0);
173}
174
175void CreateFolder(const char* path)
176{
177 mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
178}
179
181{
182 return getenv("HOME");
183}
184
185std::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
199void 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
209std::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
238std::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
Central state/object manager and communications hub.
Platform-specific utilities. We use narrow UTF-8 encoded strings as paths. Inspired by http://utf8eve...
std::time_t GetFileLastModifiedTime(std::string const &path)
void CreateFolder(const char *path)
Path must be UTF-8 encoded.
std::string GetExecutablePath()
Returns UTF-8 path or empty string on error.
std::string GetUserHomeDirectory()
Returns UTF-8 path or empty string on error.
void OpenUrlInDefaultBrowser(std::string const &url)
bool FolderExists(const char *path)
Path must be UTF-8 encoded.
char PATH_SLASH
std::string GetParentDirectory(const char *src_buff)
Returns UTF-8 path without trailing slash.
bool FileExists(const char *path)
Path must be UTF-8 encoded.
void Log(const char *msg)
The ultimate, application-wide logging function. Adds a line (any length) in 'RoR....
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.