/*
* Copyright 2010 OpenXcom Developers.
*
* This file is part of OpenXcom.
*
* OpenXcom is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenXcom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenXcom. If not, see .
*/
#include "CrossPlatform.h"
#include
#include
#include
#include "Exception.h"
#include "Options.h"
#ifdef _WIN32
#include
#include
#include
#include
#ifndef SHGFP_TYPE_CURRENT
#define SHGFP_TYPE_CURRENT 0
#endif
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "shlwapi.lib")
#else
#include
#include
#include
#include
#include
#include
#include
#endif
namespace OpenXcom
{
namespace CrossPlatform
{
/**
* Takes a filename and tries to find it in the game's DATA folder,
* accounting for the system's case-sensitivity and path style.
* @param filename Original filename.
* @return Correct filename or exception if it doesn't exist.
* @note There's no actual method for figuring out the correct
* filename on case-sensitive systems, this is just a workaround.
*/
std::string getDataFile(const std::string &filename)
{
// Correct folder separator
std::string newName = filename;
#ifdef _WIN32
std::replace(newName.begin(), newName.end(), '/', '\\');
#endif
std::string newPath = Options::getDataFolder() + filename;
// Try lowercase and uppercase names
struct stat info;
if (stat(newPath.c_str(), &info) == 0)
{
return newPath;
}
else
{
std::transform(newName.begin(), newName.end(), newName.begin(), toupper);
newPath = Options::getDataFolder() + newName;
if (stat(newPath.c_str(), &info) == 0)
{
return newPath;
}
else
{
std::transform(newName.begin(), newName.end(), newName.begin(), tolower);
newPath = Options::getDataFolder() + newName;
if (stat(newPath.c_str(), &info) == 0)
{
return newPath;
}
else
{
//throw Exception("Couldn't find " + filename);
return "";
}
}
}
}
/**
* Displays a message box with an error message.
* @param error Error message.
*/
void showError(const std::string &error)
{
#ifdef _WIN32
MessageBoxA(NULL, error.c_str(), "OpenXcom Error", MB_ICONERROR | MB_OK);
#else
std::cerr << "ERROR: " << error << std::endl;
#endif
}
/**
* Displays a message box with an error message.
* @param error Error message.
*/
void showError(const std::wstring &error)
{
#ifdef _WIN32
MessageBoxW(NULL, error.c_str(), L"OpenXcom Error", MB_ICONERROR | MB_OK);
#else
std::wcerr << L"ERROR: " << error << std::endl;
#endif
}
/**
* Checks a bunch of predefined paths for the Data folder according
* to the system and returns the full path.
* @param exists Check if the folder actually exists.
* @return Full path to Data folder.
*/
std::string findDataFolder(bool exists)
{
#ifdef _WIN32
char path[MAX_PATH];
// Check in AppData folder
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, path)))
{
PathAppendA(path, "OpenXcom\\");
if (!exists || PathIsDirectoryA(path))
{
return path;
}
}
// Check in binary directory
if (GetModuleFileNameA(NULL, path, MAX_PATH) != 0)
{
PathRemoveFileSpecA(path);
PathAppendA(path, "DATA\\");
if (!exists || PathIsDirectoryA(path))
{
return path;
}
}
// Check in working directory
if (GetCurrentDirectoryA(MAX_PATH, path) != 0)
{
PathAppendA(path, "DATA\\");
if (!exists || PathIsDirectoryA(path))
{
return path;
}
}
#else
struct stat info;
// Check shared directory
#ifdef __APPLE__
const char* shared = "/Users/Shared/OpenXcom/";
#else
const char* shared = "/usr/share/openxcom/";
#endif
if (!exists || (stat(shared, &info) == 0 && S_ISDIR(info.st_mode)))
{
return shared;
}
// Check working directory
const char* working = "./DATA/";
if (!exists || (stat(working, &info) == 0 && S_ISDIR(info.st_mode)))
{
return working;
}
#endif
return "";
}
/**
* Checks a bunch of predefined paths for the User folder according
* to the system and returns the full path.
* @param exists Check if the folder actually exists.
* @return Full path to User folder.
*/
std::string findUserFolder(bool exists)
{
#ifdef _WIN32
char path[MAX_PATH];
// Check in Documents folder
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path)))
{
PathAppendA(path, "OpenXcom\\");
if (!exists || PathIsDirectoryA(path))
{
return path;
}
}
// Check in binary directory
if (GetModuleFileNameA(NULL, path, MAX_PATH) != 0)
{
PathRemoveFileSpecA(path);
PathAppendA(path, "USER\\");
if (!exists || PathIsDirectoryA(path))
{
return path;
}
}
// Check in working directory
if (GetCurrentDirectoryA(MAX_PATH, path) != 0)
{
PathAppendA(path, "USER\\");
if (!exists || PathIsDirectoryA(path))
{
return path;
}
}
#else
struct stat info;
// Check HOME directory
char *home = getenv("HOME");
if (!home)
{
struct passwd* pwd = getpwuid(getuid());
home = pwd->pw_dir;
}
if (home)
{
char homePath[MAXPATHLEN];
#ifdef __APPLE__
snprintf(homePath, MAXPATHLEN, "%s/Library/Application Support/OpenXcom/", home);
#else
snprintf(homePath, MAXPATHLEN, "%s/.openxcom/", home);
#endif
if (!exists || (stat(homePath, &info) == 0 && S_ISDIR(info.st_mode)))
{
return homePath;
}
}
// Check working directory
const char* working = "./USER/";
if (!exists || (stat(working, &info) == 0 && S_ISDIR(info.st_mode)))
{
return working;
}
#endif
return "";
}
/**
* Creates a folder at the specified path.
* @note Only creates the last folder on the path.
* @param path Full path.
* @return Error code.
*/
int createFolder(const char *path)
{
#ifdef _WIN32
return _mkdir(path);
#else
return mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif
}
}
}