/*
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer 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.
Mod Organizer 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 Mod Organizer. If not, see .
*/
#include "gameinfo.h"
#include "windows_error.h"
#include "oblivioninfo.h"
#include "fallout3info.h"
#include "falloutnvinfo.h"
#include "skyriminfo.h"
#include "util.h"
#include
#include
#include
#include
#include
namespace MOShared {
GameInfo* GameInfo::s_Instance = nullptr;
GameInfo::GameInfo(const std::wstring &gameDirectory)
: m_GameDirectory(gameDirectory)
{
atexit(&cleanup);
}
void GameInfo::cleanup() {
delete GameInfo::s_Instance;
GameInfo::s_Instance = nullptr;
}
void GameInfo::identifyMyGamesDirectory(const std::wstring &file)
{
// this function attempts 3 (three!) ways to determine the correct "My Games" folder.
wchar_t myDocuments[MAX_PATH];
memset(myDocuments, '\0', MAX_PATH * sizeof(wchar_t));
m_MyGamesDirectory.clear();
// a) this is the way it should work. get the configured My Documents\My Games directory
if (::SHGetFolderPathW(nullptr, CSIDL_PERSONAL, nullptr, SHGFP_TYPE_CURRENT, myDocuments) == S_OK) {
m_MyGamesDirectory = std::wstring(myDocuments) + L"\\My Games";
}
// b) if there is no directory there, look in the default directory
if (m_MyGamesDirectory.empty()
|| !FileExists(m_MyGamesDirectory + L"\\" + file)) {
if (::SHGetFolderPathW(nullptr, CSIDL_PERSONAL, nullptr, SHGFP_TYPE_DEFAULT, myDocuments) == S_OK) {
std::wstring fromDefault = std::wstring(myDocuments) + L"\\My Games";
if (FileExists(fromDefault + L"\\" + file)) {
m_MyGamesDirectory = fromDefault;
}
}
}
// c) finally, look in the registry. This is discouraged
if (m_MyGamesDirectory.empty()
|| !FileExists(m_MyGamesDirectory + L"\\" + file)) {
std::wstring fromRegistry = getSpecialPath(L"Personal") + L"\\My Games";
if (FileExists(fromRegistry + L"\\" + file)) {
m_MyGamesDirectory = fromRegistry;
}
}
}
bool GameInfo::identifyGame(const std::wstring &searchPath)
{
if (OblivionInfo::identifyGame(searchPath)) {
s_Instance = new OblivionInfo(searchPath);
} else if (Fallout3Info::identifyGame(searchPath)) {
s_Instance = new Fallout3Info(searchPath);
} else if (FalloutNVInfo::identifyGame(searchPath)) {
s_Instance = new FalloutNVInfo(searchPath);
} else if (SkyrimInfo::identifyGame(searchPath)) {
s_Instance = new SkyrimInfo(searchPath);
}
return s_Instance != nullptr;
}
bool GameInfo::init(const std::wstring &moDirectory, const std::wstring &gamePath)
{
if (s_Instance == nullptr) {
if (gamePath.length() == 0) {
// search upward in the directory until a recognized game-binary is found
std::wstring searchPath(moDirectory);
while (!identifyGame(searchPath)) {
size_t lastSep = searchPath.find_last_of(L"/\\");
if (lastSep == std::string::npos) {
return false;
}
searchPath.erase(lastSep);
}
} else if (!identifyGame(gamePath)) {
return false;
}
}
return true;
}
GameInfo &GameInfo::instance()
{
assert(s_Instance != nullptr && "gameinfo not yet initialized");
return *s_Instance;
}
std::wstring GameInfo::getGameDirectory() const
{
return m_GameDirectory;
}
std::wstring GameInfo::getSpecialPath(LPCWSTR name) const
{
HKEY key;
LONG errorcode = ::RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders",
0, KEY_QUERY_VALUE, &key);
if (errorcode != ERROR_SUCCESS) {
throw windows_error("failed to look up special folder (path)", errorcode);
}
WCHAR temp[MAX_PATH];
DWORD bufferSize = MAX_PATH;
errorcode = ::RegQueryValueExW(key, name, nullptr, nullptr, (LPBYTE)temp, &bufferSize);
if (errorcode != ERROR_SUCCESS) {
throw windows_error((boost::format("failed to look up special folder (%1%)") % ToString(name, true)).str(), errorcode);
}
WCHAR temp2[MAX_PATH];
// try to expand variables in the path, if any
if (::ExpandEnvironmentStringsW(temp, temp2, MAX_PATH) != 0) {
return temp2;
} else {
return temp;
}
}
} // namespace MOShared