diff --git a/src/db/Db2Xml.cpp b/src/db/Db2Xml.cpp index 74b0225..590c13c 100644 --- a/src/db/Db2Xml.cpp +++ b/src/db/Db2Xml.cpp @@ -23,44 +23,37 @@ https://github.com/sago007/oastat/ #include "Db2Xml.hpp" #include +#include "../sago/platform_folders.h" -using std::cout; -using std::ofstream; -using std::string; -using std::stringstream; Db2Xml::Db2Xml() { psoudo_playerids.clear(); nextId = 1; - boost::format path("%1%/oastat"); - path % getenv("HOME"); - p_output_dir = path.str(); - boost::format fmkdir("mkdir -p %1%"); + p_output_dir = sago::getCacheDir()+"/oastat/xml/"; + boost::format fmkdir("mkdir -p \"%1%\""); fmkdir % p_output_dir; int fmkdir_ret = system(fmkdir.str().c_str()); if (fmkdir_ret) { - cout << "Attemting to create \"" << path << "\" with \"" << fmkdir.str() << "\", but return code was: " << fmkdir_ret << "\n"; + std::cout << "Attemting to create \"" << p_output_dir << "\" with \"" << fmkdir.str() << "\", but return code was: " << fmkdir_ret << "\n"; } } Db2Xml::Db2Xml(std::string dbargs) { - boost::format path("%1%/oastat"); - path % getenv("HOME"); - p_output_dir = path.str(); + p_output_dir = sago::getCacheDir()+"/oastat/xml/"; p_postscript = ""; psoudo_playerids.clear(); nextId = 1; //mkdir(p_output_dir.c_str()); - stringstream stream(stringstream::in | stringstream::out); + std::stringstream stream(std::stringstream::in | std::stringstream::out); stream << dbargs; - string holder; + std::string holder; //stream >> holder; while (!stream.eof()) { stream >> holder; if (!stream.eof()) { - string param; + std::string param; stream >> param; if(holder == "outputdir") { p_output_dir = param; @@ -74,7 +67,7 @@ Db2Xml::Db2Xml(std::string dbargs) fmkdir % p_output_dir; int fmkdir_ret = system(fmkdir.str().c_str()); if (fmkdir_ret) { - cout << "Attemting to create \"" << path << "\" with \"" << fmkdir.str() << "\", but return code was: " << fmkdir_ret << "\n"; + std::cout << "Attemting to create \"" << p_output_dir << "\" with \"" << fmkdir.str() << "\", but return code was: " << fmkdir_ret << "\n"; } } @@ -82,7 +75,7 @@ Db2Xml::~Db2Xml() { } -void Db2Xml::startGame(int gametype, const string &mapname, const string &basegame, const string &servername, const OaStatStruct &oss) +void Db2Xml::startGame(int gametype, const std::string &mapname, const std::string &basegame, const std::string &servername, const OaStatStruct &oss) { isOk = true; p_xmlcontent = ""; @@ -112,17 +105,17 @@ void Db2Xml::endGame(int second) if (isOk) { p_xmlcontent += (boost::format(" %1%\n") % second).str(); p_xmlcontent += "\n"; - string filename = (boost::format("%1%/%2%_%3%-%4%-%5%_%6%-%7%-%8%.xml") % p_output_dir % p_servername + std::string filename = (boost::format("%1%/%2%_%3%-%4%-%5%_%6%-%7%-%8%.xml") % p_output_dir % p_servername % (p_gametime.tm_year+1900) % (p_gametime.tm_mon+1) % (p_gametime.tm_mday) % (p_gametime.tm_hour) % (p_gametime.tm_min) % (p_gametime.tm_sec) ).str(); - ofstream outfile; + std::ofstream outfile; outfile.open (filename.c_str()); if (outfile.fail()) { - cout << "could not create " << filename << "\n"; + std::cout << "could not create " << filename << "\n"; } outfile << p_xmlcontent; outfile.close(); - cout << "End game at " << second << "with size " << p_xmlcontent.length() << " written to " << filename << "\n"; + std::cout << "End game at " << second << "with size " << p_xmlcontent.length() << " written to " << filename << "\n"; } } int Db2Xml::getGameNumber() @@ -294,7 +287,7 @@ void Db2Xml::doNotCommit() isOk = false; } -int Db2Xml::getPsoudoId(const string &guid) +int Db2Xml::getPsoudoId(const std::string &guid) { int ret = psoudo_playerids[guid]; if (ret > 0) { @@ -308,14 +301,14 @@ int Db2Xml::getPsoudoId(const string &guid) return ret; } -string Db2Xml::getXmlEscaped(const string &org) +std::string Db2Xml::getXmlEscaped(const std::string &org) { - string result = org; - boost::algorithm::replace_all(result,(string)"&",(string)"&"); - boost::algorithm::replace_all(result,(string)"<",(string)"<"); - boost::algorithm::replace_all(result,(string)">",(string)">"); - boost::algorithm::replace_all(result,(string)"\"",(string)"""); - boost::algorithm::replace_all(result,(string)"'",(string)"'"); + std::string result = org; + boost::algorithm::replace_all(result, "&", "&"); + boost::algorithm::replace_all(result, "<", "<"); + boost::algorithm::replace_all(result, ">", ">"); + boost::algorithm::replace_all(result, "\"", """); + boost::algorithm::replace_all(result, "'", "'"); return result; } diff --git a/src/oastat.cpp b/src/oastat.cpp index eef33f8..9acd1b9 100644 --- a/src/oastat.cpp +++ b/src/oastat.cpp @@ -104,8 +104,7 @@ static void addCommands(std::shared_ptr &db,std::vector > &commands) { bool done = true; - OaStatStruct *startstruct; - startstruct = NULL; + OaStatStruct *startstruct = nullptr; do { std::string line = ""; OaStatStruct oss; @@ -183,7 +182,6 @@ int main (int argc, const char* argv[]) bool doIntegrationTest = false; std::vector > commands; ///////////// - //dbargs = "mysql dbname oastat"; boost::format f("%1%/.openarena/baseoa/games.log"); f % getenv("HOME"); std::string filename = f.str(); @@ -195,7 +193,6 @@ int main (int argc, const char* argv[]) ("dbargs", boost::program_options::value(), "Arguments passed to the DB backend") ("filename,f", boost::program_options::value(), "Filename to read. Providing a blank string will read from stdin") ("config,c", boost::program_options::value >(), "Read a config file with the values. Can be given multiple times") - ("tail", "Use tail on the filename given to read the file. This will be ignored on Windows.") ("integration-test", "Perform integration test") ; boost::program_options::variables_map vm; @@ -266,7 +263,7 @@ int main (int argc, const char* argv[]) db->startGame(1,"oasago2","baseoa-mod","testserver",oss_test); db->addGenericTeamEvent(5,2,0,"sometype","","",3,4); std::cerr << "Test called\n"; - return 1; + return 0; } if (filename.length()>0) { diff --git a/src/oastatstruct.cpp b/src/oastatstruct.cpp index 5f5aa0e..895b8a4 100644 --- a/src/oastatstruct.cpp +++ b/src/oastatstruct.cpp @@ -45,19 +45,15 @@ void OaStatStruct::clear() restOfLine = ""; } -void OaStatStruct::parseLine(std::string line) +void OaStatStruct::parseLine(const std::string& orgLine) { //Parse time - //cout << line << endl; - //try{ - std::string tempTimeString = line.substr(0,7); + std::string tempTimeString = orgLine.substr(0,7); int posColon = tempTimeString.find(":"); int minute = atoi(tempTimeString.substr(0,posColon).c_str()); - /*time_t thetime = time(NULL); - gmtime_r(&thetime,&_datetime);*/ second = atoi(tempTimeString.substr(posColon+1,7).c_str()); second+=minute*60; - line = line.substr(7,line.length()); //Cut the first part of the string. + std::string line = orgLine.substr(7, orgLine.length()); //Cut the first part of the string. //Parse command name: posColon = line.find(":"); diff --git a/src/oastatstruct.h b/src/oastatstruct.h index 387fb70..3951095 100644 --- a/src/oastatstruct.h +++ b/src/oastatstruct.h @@ -50,7 +50,7 @@ public: std::string restOfLine; const tm getDateTime() const; - void parseLine(std::string line); + void parseLine(const std::string& line); void clear(); /* diff --git a/src/sago/platform_folders.cpp b/src/sago/platform_folders.cpp new file mode 100644 index 0000000..f55e4ad --- /dev/null +++ b/src/sago/platform_folders.cpp @@ -0,0 +1,400 @@ +/* +Its is under the MIT license, to encourage reuse by cut-and-paste. + +The original files are hosted here: https://github.com/sago007/PlatformFolders + +Copyright (c) 2015-2016 Poul Sander + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "platform_folders.h" +#include +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#include + +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); + if (actualSize > 0) { + //If the converted UTF-8 string could not be in the initial buffer. Allocate one that can hold it. + std::vector buffer(actualSize); + actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &buffer[0], buffer.size(), NULL, NULL); + res = buffer.data(); + } + if (actualSize == 0) { + // WideCharToMultiByte return 0 for errors. + const std::string errorMsg = "UTF16 to UTF8 failed with error code: " + GetLastError(); + throw std::runtime_error(errorMsg.c_str()); + } + 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 ) ) ) { + throw std::runtime_error(errorMsg); + } + return win32_utf16_to_utf8(szPath); +} + +static std::string GetAppData() { + return GetWindowsFolder(CSIDL_APPDATA, "RoamingAppData could not be found"); +} + +static std::string GetAppDataCommon() { + return GetWindowsFolder(CSIDL_COMMON_APPDATA, "Common appdata could not be found"); +} + +static std::string GetAppDataLocal() { + return GetWindowsFolder(CSIDL_LOCAL_APPDATA, "LocalAppData could not be found"); +} +#elif defined(__APPLE__) +#include + +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 +#include +#include +#include +#include +// For strlen and strtok +#include +//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) { + if (envValue[0] != '/') { + char buffer[200]; + std::snprintf(buffer, sizeof(buffer), "Environment \"%s\" does not start with an '/'. XDG specifies that the value must be absolute. The current value is: \"%s\"", envName, envValue); + throw std::runtime_error(buffer); + } +} + +/** + * 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; + const char* tempRes = std::getenv(envName); + if (tempRes) { + throwOnRelative(envName, tempRes); + res = tempRes; + return res; + } + res = getHome() + "/" + defaultRelativePath; + return res; +} + +static void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector& folders) { + std::vector 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& folders) { + const char* envValue = std::getenv(envName); + if (!envValue) { + envValue = defaultValue; + } + appendExtraFoldersTokenizer(envName, envValue, folders); +} + +#endif + + +namespace sago { + +std::string getDataHome() { +#if defined(_WIN32) + return GetAppData(); +#elif defined(__APPLE__) + return GetMacFolder(kApplicationSupportFolderType, "Failed to find the Application Support Folder"); +#else + return getLinuxFolderDefault("XDG_DATA_HOME", ".local/share"); +#endif +} + +std::string getConfigHome() { +#if defined(_WIN32) + return GetAppData(); +#elif defined(__APPLE__) + return GetMacFolder(kApplicationSupportFolderType, "Failed to find the Application Support Folder"); +#else + return getLinuxFolderDefault("XDG_CONFIG_HOME", ".config"); +#endif +} + +std::string getCacheDir() { +#if defined(_WIN32) + return GetAppDataLocal(); +#elif defined(__APPLE__) + return GetMacFolder(kCachedDataFolderType, "Failed to find the Application Support Folder"); +#else + return getLinuxFolderDefault("XDG_CACHE_HOME", ".cache"); +#endif +} + +void appendAdditionalDataDirectories(std::vector& homes) { +#if defined(_WIN32) + homes.push_back(GetAppDataCommon()); +#elif defined(__APPLE__) +#else + appendExtraFolders("XDG_DATA_DIRS", "/usr/local/share/:/usr/share/", homes); +#endif +} + +void appendAdditionalConfigDirectories(std::vector& homes) { +#if defined(_WIN32) + homes.push_back(GetAppDataCommon()); +#elif defined(__APPLE__) +#else + appendExtraFolders("XDG_CONFIG_DIRS", "/etc/xdg", homes); +#endif +} + +#if defined(_WIN32) +#elif defined(__APPLE__) +#else +struct PlatformFolders::PlatformFoldersData { + std::map folders; +}; + +static void PlatformFoldersAddFromFile(const std::string& filename, std::map& folders) { + std::ifstream infile(filename.c_str()); + std::string line; + while (std::getline(infile, line)) { + if (line.length() == 0 || line.at(0) == '#' || line.substr(0, 4) != "XDG_" || line.find("_DIR") == std::string::npos) { + continue; + } + try { + std::size_t splitPos = line.find('='); + std::string key = line.substr(0, splitPos); + std::size_t valueStart = line.find('"', splitPos); + std::size_t valueEnd = line.find('"', valueStart+1); + std::string value = line.substr(valueStart+1, valueEnd - valueStart - 1); + folders[key] = value; + } catch (std::exception& e) { + std::cerr << "WARNING: Failed to process \"" << line << "\" from \"" << filename << "\". Error: "<< e.what() << "\n"; + continue; + } + } +} + +static void PlatformFoldersFillData(std::map& folders) { + folders["XDG_DOCUMENTS_DIR"] = "$HOME/Documents"; + folders["XDG_DESKTOP_DIR"] = "$HOME/Desktop"; + folders["XDG_DOWNLOAD_DIR"] = "$HOME/Downloads"; + folders["XDG_MUSIC_DIR"] = "$HOME/Music"; + folders["XDG_PICTURES_DIR"] = "$HOME/Pictures"; + folders["XDG_PUBLICSHARE_DIR"] = "$HOME/Public"; + folders["XDG_TEMPLATES_DIR"] = "$HOME/.Templates"; + folders["XDG_VIDEOS_DIR"] = "$HOME/Videos"; + PlatformFoldersAddFromFile( getConfigHome()+"/user-dirs.dirs", folders); + for (std::map::iterator itr = folders.begin() ; itr != folders.end() ; ++itr ) { + std::string& value = itr->second; + if (value.compare(0, 5, "$HOME") == 0) { + value = getHome() + value.substr(5, std::string::npos); + } + } +} +#endif + +PlatformFolders::PlatformFolders() { +#if defined(_WIN32) +#elif defined(__APPLE__) +#else + this->data = new PlatformFolders::PlatformFoldersData(); + try { + PlatformFoldersFillData(data->folders); + } + catch (...) { + delete this->data; + throw; + } +#endif +} + +PlatformFolders::~PlatformFolders() { +#if defined(_WIN32) +#elif defined(__APPLE__) +#else + delete this->data; +#endif +} + +std::string PlatformFolders::getDocumentsFolder() const { +#if defined(_WIN32) + return GetWindowsFolder(CSIDL_PERSONAL, "Failed to find My Documents folder"); +#elif defined(__APPLE__) + return GetMacFolder(kDocumentsFolderType, "Failed to find Documents Folder"); +#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"); +#elif defined(__APPLE__) + return GetMacFolder(kDesktopFolderType, "Failed to find Desktop folder"); +#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"); +#elif defined(__APPLE__) + return GetMacFolder(kPictureDocumentsFolderType, "Failed to find Picture folder"); +#else + return data->folders["XDG_PICTURES_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"); +#elif defined(__APPLE__) + return GetMacFolder(kDownloadsFolderType, "Failed to find Download folder"); +#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"); +#elif defined(__APPLE__) + return GetMacFolder(kMusicDocumentsFolderType, "Failed to find Music folder"); +#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"); +#elif defined(__APPLE__) + return GetMacFolder(kMovieDocumentsFolderType, "Failed to find Movie folder"); +#else + return data->folders["XDG_VIDEOS_DIR"]; +#endif +} + +std::string PlatformFolders::getSaveGamesFolder1() const { +#if defined(_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"; +#elif defined(__APPLE__) + return GetMacFolder(kApplicationSupportFolderType, "Failed to find Application Support Folder"); +#else + return getDataHome(); +#endif +} + +std::string getDesktopFolder() { + return PlatformFolders().getDesktopFolder(); +} + +std::string getDocumentsFolder() { + return PlatformFolders().getDocumentsFolder(); +} + +std::string getDownloadFolder1() { + return PlatformFolders().getDownloadFolder1(); +} + +std::string getPicturesFolder() { + return PlatformFolders().getPicturesFolder(); +} + +std::string getMusicFolder() { + return PlatformFolders().getMusicFolder(); +} + +std::string getVideoFolder() { + return PlatformFolders().getVideoFolder(); +} + +std::string getSaveGamesFolder1() { + return PlatformFolders().getSaveGamesFolder1(); +} + + +} //namespace sago diff --git a/src/sago/platform_folders.h b/src/sago/platform_folders.h new file mode 100644 index 0000000..bd6c0d5 --- /dev/null +++ b/src/sago/platform_folders.h @@ -0,0 +1,234 @@ +/* +Its is under the MIT license, to encourage reuse by cut-and-paste. + +The original files are hosted here: https://github.com/sago007/PlatformFolders + +Copyright (c) 2015 Poul Sander + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef SAGO_PLATFORM_FOLDERS_H +#define SAGO_PLATFORM_FOLDERS_H + +#include +#include + +/** + * The namespace I use for common function. Nothing special about it. + */ +namespace sago { + +/** + * Retrives the base folder for storring 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. + */ +std::string getDataHome(); + +/** + * Retrives the base folder for storring 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. + */ +std::string getConfigHome(); + +/** + * Retrives the base folder for storring 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. + */ +std::string getCacheDir(); + +/** + * This will append extra folders that your program should be looking for data files in. + * This does not normally include the path returned by GetDataHome(). + * If you want all the folders you should do something like: + * @code{.cpp} + * vector folders; + * folders.push_back(getDataHome()); + * appendAdditionalDataDirectories(folders); + * for (string s& : folders) { + * s+="/My Program Name/"; + * } + * @endcode + * You must apply "/My Program Name/" to all the strings. + * The string at the lowest index has the highest priority. + * @param homes A vector that extra folders will be appended to. + */ +void appendAdditionalDataDirectories(std::vector& homes); + +/** + * This will append extra folders that your program should be looking for config files in. + * This does not normally include the path returned by GetConfigHome(). + * If you want all the folders you should do something like: + * @code{.cpp} + * std::vector folders; + * folders.push_back(sago::getConfigHome()); + * sago::appendAdditionalConfigDirectories(folders); + * for (std::string s& : folders) { + * s+="/My Program Name/"; + * } + * @endcode + * You must apply "/My Program Name/" to all the strings. + * The string at the lowest index has the highest priority. + * @param homes A vector that extra folders will be appended to. + */ +void appendAdditionalConfigDirectories(std::vector& homes); + +/** + * The folder that represents the desktop. + * Normally you should try not to use this folder. + * @return Absolute path to the user's desktop + */ +std::string getDesktopFolder(); + +/** + * The folder to store user documents to + * @return Absolute path to the "Documents" folder + */ +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 getDownloadFolder1(); + +/** + * The folder for storring the user's pictures. + * @return Absolute path to the "Picture" folder + */ +std::string getPicturesFolder(); + +/** + * The folder where music is stored + * @return Absolute path to the music folder + */ +std::string getMusicFolder(); + +/** + * The folder where video is stored + * @return Absolute path to the video folder + */ +std::string getVideoFolder(); + +/** + * The base folder for storring 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. + */ +std::string getSaveGamesFolder1(); + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +/** + * This class contains methods for finding the system depended special folders. + * For Windows these folders are either by convention or given by CSIDL. + * For Linux XDG convention is used. + * The Linux version has very little error checking and assumes that the config is correct + */ +class PlatformFolders { +public: + PlatformFolders(); + ~PlatformFolders(); + /** + * The folder that represents the desktop. + * Normally you should try not to use this folder. + * @return Absolute path to the user's desktop + */ + std::string getDesktopFolder() const; + /** + * The folder to store user documents to + * @return Absolute path to the "Documents" folder + */ + std::string getDocumentsFolder() const; + /** + * The folder for storring the user's pictures. + * @return Absolute path to the "Picture" folder + */ + std::string getPicturesFolder() 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. + */ + std::string getDownloadFolder1() const; + /** + * The folder where music is stored + * @return Absolute path to the music folder + */ + std::string getMusicFolder() const; + /** + * The folder where video is stored + * @return Absolute path to the video folder + */ + std::string getVideoFolder() const; + /** + * The base folder for storring saved games. + * You must add the program name to it like this: + * @code{.cpp} + * PlatformFolders pf; + * string saved_games_folder = pf.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. + */ + std::string getSaveGamesFolder1() const; +private: + PlatformFolders(const PlatformFolders&); + PlatformFolders& operator=(const PlatformFolders&); +#if defined(_WIN32) +#elif defined(__APPLE__) +#else + struct PlatformFoldersData; + PlatformFoldersData* data; +#endif +}; + +#endif // skip doxygen + + +} //namespace sago + +#endif /* PLATFORM_FOLDERS_H */