git repos / blockattack-game

commit 6b427a55

Poul Sander · 2019-02-13 17:49
6b427a5508349403a4daa1004954c93c6c781e79 patch · browse files
parent 79d552faeaa25076bdf8858c68be4645d58b04a5

Update PlatformFolders lib and make Windows 7 the minimum requirement

Changed files

M CMakeLists.txt before
M source/code/sago/platform_folders.cpp before
M source/code/sago/platform_folders.h before
diff --git a/CMakeLists.txt b/CMakeLists.txt index ad8213c..48ae458 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -31,8 +31,11 @@ if(MINGW)
endif(MINGW)
if (WIN32)
-SET(GUI_TYPE WIN32)
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686")
+ SET(GUI_TYPE WIN32)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686")
+ if(NOT _WIN32_WINNT AND NOT WINVER)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_WIN32_WINNT=0x0601 -DWINVER=0x0601")
+ endif()
endif()
if (NOT WIN32 AND NOT STANDALONE)
diff --git a/source/code/sago/platform_folders.cpp b/source/code/sago/platform_folders.cpp index f55e4ad..1c9b99c 100644 --- a/source/code/sago/platform_folders.cpp +++ b/source/code/sago/platform_folders.cpp
@@ -29,22 +29,65 @@ SOFTWARE.
#include "platform_folders.h"
#include <iostream>
#include <stdexcept>
-#include <string.h>
#include <cstdio>
#include <cstdlib>
-#if defined(_WIN32)
+#ifndef _WIN32
+
+#include <pwd.h>
+#include <unistd.h>
+
+/**
+ * Retrives the effective user's home dir.
+ * If the user is running as root we ignore the HOME environment. It works badly with sudo.
+ * Writing to $HOME as root implies security concerns that a multiplatform program cannot be assumed to handle.
+ * @return The home directory. HOME environment is respected for non-root users if it exists.
+ */
+static std::string getHome() {
+ std::string res;
+ int uid = getuid();
+ const char* homeEnv = std::getenv("HOME");
+ if ( uid != 0 && homeEnv) {
+ //We only acknowlegde HOME if not root.
+ res = homeEnv;
+ return res;
+ }
+ struct passwd* pw = getpwuid(uid);
+ if (!pw) {
+ throw std::runtime_error("Unable to get passwd struct.");
+ }
+ const char* tempRes = pw->pw_dir;
+ if (!tempRes) {
+ throw std::runtime_error("User has no home directory");
+ }
+ res = tempRes;
+ return res;
+}
+
+#endif
+
+#ifdef _WIN32
+// Make sure we don't bring in all the extra junk with windows.h
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+// stringapiset.h depends on this
#include <windows.h>
+// For SUCCEEDED macro
+#include <winerror.h>
+// For WideCharToMultiByte
+#include <stringapiset.h>
+// For SHGetFolderPathW and various CSIDL "magic numbers"
#include <shlobj.h>
static std::string win32_utf16_to_utf8(const wchar_t* wstr) {
std::string res;
// If the 6th parameter is 0 then WideCharToMultiByte returns the number of bytes needed to store the result.
- int actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
+ int actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
if (actualSize > 0) {
//If the converted UTF-8 string could not be in the initial buffer. Allocate one that can hold it.
std::vector<char> buffer(actualSize);
- actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &buffer[0], buffer.size(), NULL, NULL);
+ actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &buffer[0], buffer.size(), nullptr, nullptr);
res = buffer.data();
}
if (actualSize == 0) {
@@ -55,50 +98,46 @@ static std::string win32_utf16_to_utf8(const wchar_t* wstr) {
return res;
}
-static std::string GetWindowsFolder(int folderId, const char* errorMsg) {
- wchar_t szPath[MAX_PATH];
- szPath[0] = 0;
- if ( !SUCCEEDED( SHGetFolderPathW( NULL, folderId, NULL, 0, szPath ) ) ) {
+class FreeCoTaskMemory {
+ LPWSTR pointer = NULL;
+public:
+ explicit FreeCoTaskMemory(LPWSTR pointer) : pointer(pointer) {};
+ ~FreeCoTaskMemory() {
+ CoTaskMemFree(pointer);
+ }
+};
+
+static std::string GetKnownWindowsFolder(REFKNOWNFOLDERID folderId, const char* errorMsg) {
+ LPWSTR wszPath = NULL;
+ HRESULT hr;
+ hr = SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, NULL, &wszPath);
+ FreeCoTaskMemory scopeBoundMemory(wszPath);
+
+ if (!SUCCEEDED(hr)) {
throw std::runtime_error(errorMsg);
}
- return win32_utf16_to_utf8(szPath);
+ return win32_utf16_to_utf8(wszPath);
}
static std::string GetAppData() {
- return GetWindowsFolder(CSIDL_APPDATA, "RoamingAppData could not be found");
+ return GetKnownWindowsFolder(FOLDERID_RoamingAppData, "RoamingAppData could not be found");
}
static std::string GetAppDataCommon() {
- return GetWindowsFolder(CSIDL_COMMON_APPDATA, "Common appdata could not be found");
+ return GetKnownWindowsFolder(FOLDERID_ProgramData, "ProgramData could not be found");
}
static std::string GetAppDataLocal() {
- return GetWindowsFolder(CSIDL_LOCAL_APPDATA, "LocalAppData could not be found");
+ return GetKnownWindowsFolder(FOLDERID_LocalAppData, "LocalAppData could not be found");
}
#elif defined(__APPLE__)
-#include <CoreServices/CoreServices.h>
-
-static std::string GetMacFolder(OSType folderType, const char* errorMsg) {
- std::string ret;
- FSRef ref;
- char path[PATH_MAX];
- OSStatus err = FSFindFolder( kUserDomain, folderType, kCreateFolder, &ref );
- if (err != noErr) {
- throw std::runtime_error(errorMsg);
- }
- FSRefMakePath( &ref, (UInt8*)&path, PATH_MAX );
- ret = path;
- return ret;
-}
-
#else
#include <map>
#include <fstream>
-#include <pwd.h>
-#include <unistd.h>
#include <sys/types.h>
// For strlen and strtok
#include <cstring>
+#include <sstream>
//Typically Linux. For easy reading the comments will just say Linux but should work with most *nixes
static void throwOnRelative(const char* envName, const char* envValue) {
@@ -109,32 +148,7 @@ static void throwOnRelative(const char* envName, const char* envValue) {
}
}
-/**
- * Retrives the effective user's home dir.
- * If the user is running as root we ignore the HOME environment. It works badly with sudo.
- * Writing to $HOME as root implies security concerns that a multiplatform program cannot be assumed to handle.
- * @return The home directory. HOME environment is respected for non-root users if it exists.
- */
-static std::string getHome() {
- std::string res;
- int uid = getuid();
- const char* homeEnv = std::getenv("HOME");
- if ( uid != 0 && homeEnv) {
- //We only acknowlegde HOME if not root.
- res = homeEnv;
- return res;
- }
- struct passwd* pw = getpwuid(uid);
- if (!pw) {
- throw std::runtime_error("Unable to get passwd struct.");
- }
- const char* tempRes = pw->pw_dir;
- if (!tempRes) {
- throw std::runtime_error("User has no home directory");
- }
- res = tempRes;
- return res;
-}
+
static std::string getLinuxFolderDefault(const char* envName, const char* defaultRelativePath) {
std::string res;
@@ -148,28 +162,12 @@ static std::string getLinuxFolderDefault(const char* envName, const char* defaul
return res;
}
-static void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector<std::string>& folders) {
- std::vector<char> buffer(envValue, envValue + std::strlen(envValue) + 1);
- char* p = std::strtok ( &buffer[0], ":");
- while (p != NULL) {
- if (p[0] == '/') {
- folders.push_back(p);
- }
- else {
- //Unless the system is wrongly configured this should never happen... But of course some systems will be incorectly configured.
- //The XDG documentation indicates that the folder should be ignored but that the program should continue.
- std::cerr << "Skipping path \"" << p << "\" in \"" << envName << "\" because it does not start with a \"/\"\n";
- }
- p = std::strtok (NULL, ":");
- }
-}
-
static void appendExtraFolders(const char* envName, const char* defaultValue, std::vector<std::string>& folders) {
const char* envValue = std::getenv(envName);
if (!envValue) {
envValue = defaultValue;
}
- appendExtraFoldersTokenizer(envName, envValue, folders);
+ sago::internal::appendExtraFoldersTokenizer(envName, envValue, folders);
}
#endif
@@ -177,57 +175,72 @@ static void appendExtraFolders(const char* envName, const char* defaultValue, st
namespace sago {
+#if !defined(_WIN32) && !defined(__APPLE__)
+namespace internal {
+ void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector<std::string>& folders) {
+ std::stringstream ss(envValue);
+ std::string value;
+ while (std::getline(ss, value, ':')) {
+ if (value[0] == '/') {
+ folders.push_back(value);
+ }
+ else {
+ //Unless the system is wrongly configured this should never happen... But of course some systems will be incorectly configured.
+ //The XDG documentation indicates that the folder should be ignored but that the program should continue.
+ std::cerr << "Skipping path \"" << value << "\" in \"" << envName << "\" because it does not start with a \"/\"\n";
+ }
+ }
+ }
+}
+#endif
+
std::string getDataHome() {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetAppData();
#elif defined(__APPLE__)
- return GetMacFolder(kApplicationSupportFolderType, "Failed to find the Application Support Folder");
+ return getHome()+"/Library/Application Support";
#else
return getLinuxFolderDefault("XDG_DATA_HOME", ".local/share");
#endif
}
std::string getConfigHome() {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetAppData();
#elif defined(__APPLE__)
- return GetMacFolder(kApplicationSupportFolderType, "Failed to find the Application Support Folder");
+ return getHome()+"/Library/Application Support";
#else
return getLinuxFolderDefault("XDG_CONFIG_HOME", ".config");
#endif
}
std::string getCacheDir() {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetAppDataLocal();
#elif defined(__APPLE__)
- return GetMacFolder(kCachedDataFolderType, "Failed to find the Application Support Folder");
+ return getHome()+"/Library/Caches";
#else
return getLinuxFolderDefault("XDG_CACHE_HOME", ".cache");
#endif
}
void appendAdditionalDataDirectories(std::vector<std::string>& homes) {
-#if defined(_WIN32)
+#ifdef _WIN32
homes.push_back(GetAppDataCommon());
-#elif defined(__APPLE__)
-#else
+#elif !defined(__APPLE__)
appendExtraFolders("XDG_DATA_DIRS", "/usr/local/share/:/usr/share/", homes);
#endif
}
void appendAdditionalConfigDirectories(std::vector<std::string>& homes) {
-#if defined(_WIN32)
+#ifdef _WIN32
homes.push_back(GetAppDataCommon());
-#elif defined(__APPLE__)
-#else
+#elif !defined(__APPLE__)
appendExtraFolders("XDG_CONFIG_DIRS", "/etc/xdg", homes);
#endif
}
-#if defined(_WIN32)
-#elif defined(__APPLE__)
-#else
+#if !defined(_WIN32) && !defined(__APPLE__)
struct PlatformFolders::PlatformFoldersData {
std::map<std::string, std::string> folders;
};
@@ -273,9 +286,7 @@ static void PlatformFoldersFillData(std::map<std::string, std::string>& folders)
#endif
PlatformFolders::PlatformFolders() {
-#if defined(_WIN32)
-#elif defined(__APPLE__)
-#else
+#if !defined(_WIN32) && !defined(__APPLE__)
this->data = new PlatformFolders::PlatformFoldersData();
try {
PlatformFoldersFillData(data->folders);
@@ -288,81 +299,88 @@ PlatformFolders::PlatformFolders() {
}
PlatformFolders::~PlatformFolders() {
-#if defined(_WIN32)
-#elif defined(__APPLE__)
-#else
+#if !defined(_WIN32) && !defined(__APPLE__)
delete this->data;
#endif
}
std::string PlatformFolders::getDocumentsFolder() const {
-#if defined(_WIN32)
- return GetWindowsFolder(CSIDL_PERSONAL, "Failed to find My Documents folder");
+#ifdef _WIN32
+ return GetKnownWindowsFolder(FOLDERID_Documents, "Failed to find My Documents folder");
#elif defined(__APPLE__)
- return GetMacFolder(kDocumentsFolderType, "Failed to find Documents Folder");
+ return getHome()+"/Documents";
#else
return data->folders["XDG_DOCUMENTS_DIR"];
#endif
}
std::string PlatformFolders::getDesktopFolder() const {
-#if defined(_WIN32)
- return GetWindowsFolder(CSIDL_DESKTOP, "Failed to find Desktop folder");
+#ifdef _WIN32
+ return GetKnownWindowsFolder(FOLDERID_Desktop, "Failed to find Desktop folder");
#elif defined(__APPLE__)
- return GetMacFolder(kDesktopFolderType, "Failed to find Desktop folder");
+ return getHome()+"/Desktop";
#else
return data->folders["XDG_DESKTOP_DIR"];
#endif
}
std::string PlatformFolders::getPicturesFolder() const {
-#if defined(_WIN32)
- return GetWindowsFolder(CSIDL_MYPICTURES, "Failed to find My Pictures folder");
+#ifdef _WIN32
+ return GetKnownWindowsFolder(FOLDERID_Pictures, "Failed to find My Pictures folder");
#elif defined(__APPLE__)
- return GetMacFolder(kPictureDocumentsFolderType, "Failed to find Picture folder");
+ return getHome()+"/Pictures";
#else
return data->folders["XDG_PICTURES_DIR"];
#endif
}
+std::string PlatformFolders::getPublicFolder() const {
+#ifdef _WIN32
+ return GetKnownWindowsFolder(FOLDERID_Public, "Failed to find the Public folder");
+#elif defined(__APPLE__)
+ return getHome()+"/Public";
+#else
+ return data->folders["XDG_PUBLICSHARE_DIR"];
+#endif
+}
+
std::string PlatformFolders::getDownloadFolder1() const {
-#if defined(_WIN32)
- //Pre Vista. Files was downloaded to the desktop
- return GetWindowsFolder(CSIDL_DESKTOP, "Failed to find My Downloads (Desktop) folder");
+#ifdef _WIN32
+ return GetKnownWindowsFolder(FOLDERID_Downloads, "Failed to find My Downloads folder");
#elif defined(__APPLE__)
- return GetMacFolder(kDownloadsFolderType, "Failed to find Download folder");
+ return getHome()+"/Downloads";
#else
return data->folders["XDG_DOWNLOAD_DIR"];
#endif
}
std::string PlatformFolders::getMusicFolder() const {
-#if defined(_WIN32)
- return GetWindowsFolder(CSIDL_MYMUSIC, "Failed to find My Music folder");
+#ifdef _WIN32
+ return GetKnownWindowsFolder(FOLDERID_Music, "Failed to find My Music folder");
#elif defined(__APPLE__)
- return GetMacFolder(kMusicDocumentsFolderType, "Failed to find Music folder");
+ return getHome()+"/Music";
#else
return data->folders["XDG_MUSIC_DIR"];
#endif
}
std::string PlatformFolders::getVideoFolder() const {
-#if defined(_WIN32)
- return GetWindowsFolder(CSIDL_MYVIDEO, "Failed to find My Video folder");
+#ifdef _WIN32
+ return GetKnownWindowsFolder(FOLDERID_Videos, "Failed to find My Video folder");
#elif defined(__APPLE__)
- return GetMacFolder(kMovieDocumentsFolderType, "Failed to find Movie folder");
+ return getHome()+"/Movies";
#else
return data->folders["XDG_VIDEOS_DIR"];
#endif
}
std::string PlatformFolders::getSaveGamesFolder1() const {
-#if defined(_WIN32)
+#ifdef _WIN32
//A dedicated Save Games folder was not introduced until Vista. For XP and older save games are most often saved in a normal folder named "My Games".
//Data that should not be user accessible should be placed under GetDataHome() instead
- return GetWindowsFolder(CSIDL_PERSONAL, "Failed to find My Documents folder")+"\\My Games";
+ return GetKnownWindowsFolder(FOLDERID_Documents, "Failed to find My Documents folder")+"\\My Games";
#elif defined(__APPLE__)
- return GetMacFolder(kApplicationSupportFolderType, "Failed to find Application Support Folder");
+ return getHome()+"/Library/Application Support";
#else
return getDataHome();
#endif
@@ -376,14 +394,22 @@ std::string getDocumentsFolder() {
return PlatformFolders().getDocumentsFolder();
}
-std::string getDownloadFolder1() {
+std::string getDownloadFolder() {
return PlatformFolders().getDownloadFolder1();
}
+std::string getDownloadFolder1() {
+ return getDownloadFolder();
+}
+
std::string getPicturesFolder() {
return PlatformFolders().getPicturesFolder();
}
+std::string getPublicFolder() {
+ return PlatformFolders().getPublicFolder();
+}
+
std::string getMusicFolder() {
return PlatformFolders().getMusicFolder();
}
@@ -396,5 +422,12 @@ std::string getSaveGamesFolder1() {
return PlatformFolders().getSaveGamesFolder1();
}
+std::string getSaveGamesFolder2() {
+#ifdef _WIN32
+ return GetKnownWindowsFolder(FOLDERID_SavedGames, "Failed to find Saved Games folder");
+#else
+ return PlatformFolders().getSaveGamesFolder1();
+#endif
+}
} //namespace sago
diff --git a/source/code/sago/platform_folders.h b/source/code/sago/platform_folders.h index bd6c0d5..fc9dd3b 100644 --- a/source/code/sago/platform_folders.h +++ b/source/code/sago/platform_folders.h
@@ -37,39 +37,47 @@ SOFTWARE.
*/
namespace sago {
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+namespace internal {
+ #if !defined(_WIN32) && !defined(__APPLE__)
+ void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector<std::string>& folders);
+ #endif
+}
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
/**
- * Retrives the base folder for storring data files.
+ * Retrives the base folder for storing data files.
* You must add the program name yourself like this:
* @code{.cpp}
* string data_home = getDataHome()+"/My Program Name/";
* @endcode
* On Windows this defaults to %APPDATA% (Roaming profile)
* On Linux this defaults to ~/.local/share but can be configured
- * @return The base folder for storring program data.
+ * @return The base folder for storing program data.
*/
std::string getDataHome();
/**
- * Retrives the base folder for storring config files.
+ * Retrives the base folder for storing config files.
* You must add the program name yourself like this:
* @code{.cpp}
* string data_home = getConfigHome()+"/My Program Name/";
* @endcode
* On Windows this defaults to %APPDATA% (Roaming profile)
* On Linux this defaults to ~/.config but can be configured
- * @return The base folder for storring config data.
+ * @return The base folder for storing config data.
*/
std::string getConfigHome();
/**
- * Retrives the base folder for storring cache files.
+ * Retrives the base folder for storing cache files.
* You must add the program name yourself like this:
* @code{.cpp}
* string data_home = getCacheDir()+"/My Program Name/";
* @endcode
* On Windows this defaults to %APPDATALOCAL%
* On Linux this defaults to ~/.cache but can be configured
- * @return The base folder for storring data that do not need to be backed up.
+ * @return The base folder for storing data that do not need to be backed up.
*/
std::string getCacheDir();
@@ -124,18 +132,30 @@ std::string getDocumentsFolder();
/**
* The folder where files are downloaded.
- * @note Windows: This version is XP compatible and returns the Desktop. Vista and later has a dedicated folder.
+ * @return Absolute path to the folder where files are downloaded to.
+ */
+std::string getDownloadFolder();
+
+/**
+ * The folder where files are downloaded.
+ * @note This is provided for backward compatibility. Use getDownloadFolder instead.
* @return Absolute path to the folder where files are downloaded to.
*/
std::string getDownloadFolder1();
/**
- * The folder for storring the user's pictures.
+ * The folder for storing the user's pictures.
* @return Absolute path to the "Picture" folder
*/
std::string getPicturesFolder();
/**
+ * This returns the folder that can be used for sharing files with other users on the same system.
+ * @return Absolute path to the "Public" folder
+ */
+std::string getPublicFolder();
+
+/**
* The folder where music is stored
* @return Absolute path to the music folder
*/
@@ -148,17 +168,31 @@ std::string getMusicFolder();
std::string getVideoFolder();
/**
- * The base folder for storring saved games.
+ * A base folder for storing saved games.
* You must add the program name to it like this:
* @code{.cpp}
* string saved_games_folder = sago::getSaveGamesFolder1()+"/My Program Name/";
* @endcode
* @note Windows: This is an XP compatible version and returns the path to "My Games" in Documents. Vista and later has an official folder.
* @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome()
- * @return The folder base folder for storring save games.
+ * @return The folder base folder for storing save games.
*/
std::string getSaveGamesFolder1();
+/**
+ * A base folder for storing saved games.
+ * You must add the program name to it like this:
+ * @code{.cpp}
+ * string saved_games_folder = sago::getSaveGamesFolder2()+"/My Program Name/";
+ * @endcode
+ * @note PlatformFolders provide different folders to for saved games as not all operating systems has support for Saved Games yet.
+ * It is recommended to pick the highest number (currently getSaveGamesFolder2) at the time your product enters production and stick with it
+ * @note Windows: This returns the "Saved Games" folder. This folder exist in Vista and later
+ * @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome()
+ * @return The folder base folder for storing save games.
+ */
+std::string getSaveGamesFolder2();
+
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/**
@@ -183,11 +217,15 @@ public:
*/
std::string getDocumentsFolder() const;
/**
- * The folder for storring the user's pictures.
+ * The folder for storing the user's pictures.
* @return Absolute path to the "Picture" folder
*/
std::string getPicturesFolder() const;
/**
+ * Use sago::getPublicFolder() instead!
+ */
+ std::string getPublicFolder() const;
+ /**
* The folder where files are downloaded.
* @note Windows: This version is XP compatible and returns the Desktop. Vista and later has a dedicated folder.
* @return Absolute path to the folder where files are downloaded to.
@@ -204,7 +242,7 @@ public:
*/
std::string getVideoFolder() const;
/**
- * The base folder for storring saved games.
+ * The base folder for storing saved games.
* You must add the program name to it like this:
* @code{.cpp}
* PlatformFolders pf;
@@ -212,15 +250,13 @@ public:
* @endcode
* @note Windows: This is an XP compatible version and returns the path to "My Games" in Documents. Vista and later has an official folder.
* @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome()
- * @return The folder base folder for storring save games.
+ * @return The folder base folder for storing save games.
*/
std::string getSaveGamesFolder1() const;
private:
PlatformFolders(const PlatformFolders&);
PlatformFolders& operator=(const PlatformFolders&);
-#if defined(_WIN32)
-#elif defined(__APPLE__)
-#else
+#if !defined(_WIN32) && !defined(__APPLE__)
struct PlatformFoldersData;
PlatformFoldersData* data;
#endif