xoreos  0.0.5
platform.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include "src/common/system.h"
26 
27 #if defined(WIN32)
28  #define WIN32_LEAN_AND_MEAN
29  #include <windows.h>
30  #include <shellapi.h>
31  #include <wchar.h>
32 #endif
33 
34 #if defined(UNIX)
35  #include <pwd.h>
36  #include <unistd.h>
37 #endif
38 
39 #include <cassert>
40 #include <cstdlib>
41 
42 #include <boost/locale.hpp>
43 #include <boost/filesystem/path.hpp>
44 
45 #include "src/common/platform.h"
46 #include "src/common/error.h"
47 #include "src/common/scopedptr.h"
48 #include "src/common/encoding.h"
49 #include "src/common/filepath.h"
50 
51 namespace Common {
52 
54  /* Imbue Boost.Filesystem with a locale converting between UTF-8 and the
55  * local encoding. This allows us to work with UTF-8 everywhere. */
56 
57  try {
58  boost::filesystem::path::imbue(boost::locale::generator().generate(""));
59  } catch (std::exception &se) {
60  throw Exception(se);
61  }
62 }
63 
64 // .--- getParameters() ---.
65 #if defined(WIN32)
66 
67 /* On Windows, we're not going to use the passed-in argc and argv, since those are
68  * usually in a local 8-bit encoding. Instead, we're calling Windows functions to
69  * get the parameters in UTF-16, and convert them. */
70 void Platform::getParameters(int UNUSED(argc), char **UNUSED(argv), std::vector<UString> &args) {
71  int argc;
72  wchar_t **argv = CommandLineToArgvW(GetCommandLineW(), &argc);
73 
74  args.clear();
75  if (argc <= 0)
76  return;
77 
78  args.reserve(argc);
79 
80  for (int i = 0; i < argc; i++)
81  args.push_back(readString(reinterpret_cast<const byte *>(argv[i]), wcslen(argv[i]) * 2, kEncodingUTF16LE));
82 }
83 
84 #else
85 
86 /* On non-Windows system, we assume the parameters are already in UTF-8. */
87 void Platform::getParameters(int argc, char **argv, std::vector<UString> &args) {
88  args.clear();
89  if (argc <= 0)
90  return;
91 
92  args.reserve(argc);
93 
94  for (int i = 0; i < argc; i++)
95  args.push_back(argv[i]);
96 }
97 
98 #endif
99 // '--- getParameters() ---'
100 
101 // .--- openFile() ---.
102 std::FILE *Platform::openFile(const UString &fileName, FileMode mode) {
103  assert(((uint) mode) < kFileModeMAX);
104 
105  std::FILE *file = 0;
106 
107 #if defined(WIN32)
108  static const wchar_t * const modeStrings[kFileModeMAX] = { L"rb", L"wb" };
109 
110  file = _wfopen(boost::filesystem::path(fileName.c_str()).c_str(), modeStrings[(uint) mode]);
111 #else
112  static const char * const modeStrings[kFileModeMAX] = { "rb", "wb" };
113 
114  file = std::fopen(boost::filesystem::path(fileName.c_str()).c_str(), modeStrings[(uint) mode]);
115 #endif
116 
117  return file;
118 }
119 // '--- openFile() ---'
120 
121 // .--- Windows utility functions ---.
122 #if defined(WIN32)
123 
124 enum WindowsVersion {
125  kWindowsVersionUnknown = 0x00000000,
126  kWindowsVersion2000 = 0x00050000,
127  kWindowsVersionXP = 0x00050001,
128  kWindowsVersionXPProf = 0x00050002,
129  kWindowsVersionVista = 0x00060000,
130  kWindowsVersion7 = 0x00060001,
131  kWindowsVersion8 = 0x00060002,
132  kWindowsVersion8_1 = 0x00060003,
133  kWindowsVersion10 = 0x000A0000
134 };
135 
136 static bool isWindowsVersionOrGreater(uint16 majorVersion, uint16 minorVersion) {
137  OSVERSIONINFOEX osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
138 
139  DWORDLONG condition =
140  VerSetConditionMask(VerSetConditionMask(
141  0, VER_MAJORVERSION, VER_GREATER_EQUAL),
142  VER_MINORVERSION, VER_GREATER_EQUAL);
143 
144  osvi.dwMajorVersion = majorVersion;
145  osvi.dwMinorVersion = minorVersion;
146 
147  return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, condition) != 0;
148 }
149 
150 static WindowsVersion getWindowsVersion() {
151  static const int16 kWindowsVersionMax = 20;
152 
153  for (int16 i = kWindowsVersionMax; i >= 0; i--)
154  for (int16 j = 5; j >= 0; j--)
155  if (isWindowsVersionOrGreater(i, j))
156  return (WindowsVersion) ((i << 16) + j);
157 
158  return kWindowsVersionUnknown;
159 }
160 
161 static inline UString getWindowsVariable(const wchar_t *variable) {
162  DWORD length = GetEnvironmentVariableW(variable, 0, 0);
163  if (!length)
164  return "";
165 
166  const size_t size = length * sizeof(wchar_t);
167  ScopedArray<byte> data(new byte[size]);
168 
169  DWORD newLength = GetEnvironmentVariableW(variable, reinterpret_cast<wchar_t *>(data.get()), length);
170  if (!newLength || (newLength > length))
171  return "";
172 
173  return readString(data.get(), size, kEncodingUTF16LE);
174 }
175 
176 #endif
177 // '--- Windows utility functions ---'
178 
179 // .--- OS-specific directories ---.
181  UString directory;
182 
183 #if defined(WIN32)
184  // Windows: $USERPROFILE
185 
186  directory = getWindowsVariable(L"USERPROFILE");
187 
188 #elif defined(UNIX)
189  // Default Unixoid: $HOME. As a fallback, search the passwd file
190 
191  const char *pathStr = getenv("HOME");
192  if (!pathStr) {
193  struct passwd *pwd = getpwuid(getuid());
194  if (pwd)
195  pathStr = pwd->pw_dir;
196  }
197 
198  if (pathStr)
199  directory = pathStr;
200 
201 #endif
202 
203  return directory;
204 }
205 
207  UString directory;
208 
209 #if defined(WIN32)
210  // Windows: $APPDATA/xoreos/ or $USERPROFILE/xoreos/ or ./
211 
212  const WindowsVersion windowsVersion = getWindowsVersion();
213 
214  if (windowsVersion >= kWindowsVersion2000) {
215  // Try the Application Data directory
216  directory = getWindowsVariable(L"APPDATA");
217  if (!directory.empty())
218  directory += "\\xoreos";
219 
220  // Try the User Profile directory
221  if (directory.empty()) {
222  directory = getWindowsVariable(L"USERPROFILE");
223  if (!directory.empty())
224  directory += "\\xoreos";
225  }
226  }
227 
228  // If all else fails (or the Windows version is too low), use the current directory
229  if (directory.empty())
230  directory = ".";
231 
232 #elif defined(MACOSX)
233  // Mac OS X: ~/Library/Preferences/xoreos/
234 
235  directory = getHomeDirectory();
236  if (!directory.empty())
237  directory += "/Library/Preferences/xoreos";
238 
239  if (directory.empty())
240  directory = ".";
241 
242 #elif defined(UNIX)
243  // Default Unixoid: $XDG_CONFIG_HOME/xoreos/ or ~/.config/xoreos/
244 
245  const char *pathStr = getenv("XDG_CONFIG_HOME");
246  if (pathStr) {
247  directory = UString(pathStr) + "/xoreos";
248  } else {
249  directory = getHomeDirectory();
250  if (!directory.empty())
251  directory += "/.config/xoreos";
252  }
253 
254  if (directory.empty())
255  directory = ".";
256 
257 #else
258  // Fallback: Current directory
259 
260  directory = ".";
261 #endif
262 
263  return FilePath::canonicalize(directory);
264 }
265 
267  UString directory;
268 
269 #if defined(WIN32)
270  // Windows: Same as getConfigDirectory()
271  directory = getConfigDirectory();
272 #elif defined(MACOSX)
273  // Mac OS X: ~/Library/Application\ Support/xoreos/
274 
275  directory = getHomeDirectory();
276  if (!directory.empty())
277  directory += "/Library/Application Support/xoreos";
278 
279  if (directory.empty())
280  directory = ".";
281 
282 #elif defined(UNIX)
283  // Default Unixoid: $XDG_DATA_HOME/xoreos/ or ~/.local/share/xoreos/
284 
285  const char *pathStr = getenv("XDG_DATA_HOME");
286  if (pathStr) {
287  directory = UString(pathStr) + "/xoreos";
288  } else {
289  directory = getHomeDirectory();
290  if (!directory.empty())
291  directory += "/.local/share/xoreos";
292  }
293 
294  if (directory.empty())
295  directory = ".";
296 
297 #else
298  // Fallback: Same as getConfigDirectory()
299  directory = getConfigDirectory();
300 #endif
301 
302  return FilePath::canonicalize(directory);
303 }
304 // '--- OS-specific directories ---'
305 
306 } // End of namespace Common
static UString getHomeDirectory()
Return the OS-specific path of the user&#39;s home directory.
Definition: platform.cpp:180
Definition: 2dafile.h:39
A class holding an UTF-8 string.
Definition: ustring.h:48
static UString getUserDataDirectory()
Return the OS-specific path of the user data directory.
Definition: platform.cpp:266
UTF-16 LE (little endian).
Definition: encoding.h:44
static void getParameters(int argc, char **argv, std::vector< UString > &args)
Read the command line parameters into UTF-8 strings.
Definition: platform.cpp:87
Platform-dependant functions, mostly for internal use in the Common namespace.
int16_t int16
Definition: types.h:201
A simple scoped smart pointer template.
static UString getConfigDirectory()
Return the OS-specific path of the config directory.
Definition: platform.cpp:206
Basic exceptions to throw.
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
uint16_t uint16
Definition: types.h:202
#define UNUSED(x)
Definition: system.h:170
static UString canonicalize(const UString &p, bool resolveSymLinks=true)
Return the canonical, absolutized and normalized path.
Definition: filepath.cpp:230
Utility functions for working with differing string encodings.
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
static std::FILE * openFile(const UString &fileName, FileMode mode)
Open a file with an UTF-8 encoded name.
Definition: platform.cpp:102
StackException Exception
Definition: error.h:59
Low-level detection of architecture/system properties.
UString readString(SeekableReadStream &stream, Encoding encoding)
Read a string with the given encoding of a stream.
Definition: encoding.cpp:287
static void init()
Initialize platform-dependant things.
Definition: platform.cpp:53
Utility class for manipulating file paths.
uint8 byte
Definition: types.h:209
unsigned int uint
Definition: types.h:211