File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Expand Up @@ -16,4 +16,3 @@ PH_SZFar = 0
PH_ExtraParam = 0
PH_ZNear =
PH_ZFar =
[Gecko]
Expand Up @@ -12,6 +12,5 @@ PH_SZFar = 0
PH_ExtraParam = 0
PH_ZNear =
PH_ZFar =
[Gecko]
[Video_Settings]
SafeTextureCacheColorSamples = 512
File renamed without changes.
File renamed without changes.
File renamed without changes.
Expand Up @@ -12,7 +12,6 @@ PH_SZFar = 0
PH_ExtraParam = 0
PH_ZNear =
PH_ZFar =
[Gecko]
[Video_Settings]
UseXFB = True
UseRealXFB = False
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Expand Up @@ -12,7 +12,6 @@ PH_SZFar = 0
PH_ExtraParam = 0
PH_ZNear =
PH_ZFar =
[Gecko]
[Video_Settings]
UseXFB = True
UseRealXFB = False
Expand Down
Expand Up @@ -16,6 +16,5 @@ PH_SZFar = 0
PH_ExtraParam = 0
PH_ZNear =
PH_ZFar =
[Gecko]
[Video_Settings]
SafeTextureCacheColorSamples = 512
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
Binary file removed Data/Sys/Wii/setting-kor.txt
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Expand Up @@ -64,10 +64,9 @@ public void onCreate(Bundle savedInstanceState)
String BaseDir = Environment.getExternalStorageDirectory()+File.separator+"dolphin-emu";
String ConfigDir = BaseDir + File.separator + "Config";
String GCDir = BaseDir + File.separator + "GC";
String WiiDir = BaseDir + File.separator + "Wii";

// Copy assets if needed
File file = new File(WiiDir + File.separator + "setting-usa.txt");
File file = new File(GCDir + File.separator + "font_sjis.bin");
if(!file.exists())
{
NativeLibrary.CreateUserFolders();
Expand All @@ -81,10 +80,6 @@ public void onCreate(Bundle savedInstanceState)
CopyAsset("dsp_rom.bin", GCDir + File.separator + "dsp_rom.bin");
CopyAsset("font_ansi.bin", GCDir + File.separator + "font_ansi.bin");
CopyAsset("font_sjis.bin", GCDir + File.separator + "font_sjis.bin");
CopyAsset("setting-eur.txt", WiiDir + File.separator + "setting-eur.txt");
CopyAsset("setting-jpn.txt", WiiDir + File.separator + "setting-jpn.txt");
CopyAsset("setting-kor.txt", WiiDir + File.separator + "setting-kor.txt");
CopyAsset("setting-usa.txt", WiiDir + File.separator + "setting-usa.txt");
}

// Load the configuration keys set in the Dolphin ini and gfx ini files
Expand Down
7 changes: 1 addition & 6 deletions Source/Core/Common/Src/CommonPaths.h
Expand Up @@ -40,18 +40,13 @@
#define SYSDATA_DIR "Sys"
#elif defined __APPLE__
#define SYSDATA_DIR "Contents/Resources/Sys"
#define SHARED_USER_DIR File::GetBundleDirectory() + \
DIR_SEP USERDATA_DIR DIR_SEP
#elif defined ANDROID
#define SYSDATA_DIR "/sdcard/dolphin-emu"
#define SHARED_USER_DIR SYSDATA_DIR
#else
#ifdef DATA_DIR
#define SYSDATA_DIR DATA_DIR "sys"
#define SHARED_USER_DIR DATA_DIR USERDATA_DIR DIR_SEP
#else
#define SYSDATA_DIR "sys"
#define SHARED_USER_DIR ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP
#endif
#endif

Expand All @@ -64,7 +59,7 @@
#define GC_USER_DIR "GC"
#define WII_USER_DIR "Wii"
#define CONFIG_DIR "Config"
#define GAMECONFIG_DIR "GameConfig"
#define GAMESETTINGS_DIR "GameSettings"
#define MAPS_DIR "Maps"
#define CACHE_DIR "Cache"
#define SHADERCACHE_DIR "ShaderCache"
Expand Down
147 changes: 103 additions & 44 deletions Source/Core/Common/Src/FileUtil.cpp
Expand Up @@ -551,22 +551,34 @@ bool DeleteDirRecursively(const std::string &directory)
// Create directory and copy contents (does not overwrite existing files)
void CopyDir(const std::string &source_path, const std::string &dest_path)
{
#ifndef _WIN32
if (source_path == dest_path) return;
if (!File::Exists(source_path)) return;
if (!File::Exists(dest_path)) File::CreateFullPath(dest_path);

#ifdef _WIN32
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile(UTF8ToTStr(source_path + "\\*").c_str(), &ffd);

if (hFind == INVALID_HANDLE_VALUE)
{
FindClose(hFind);
return;
}

do
{
const std::string virtualName(TStrToUTF8(ffd.cFileName));
#else
struct dirent dirent, *result = NULL;
DIR *dirp = opendir(source_path.c_str());
if (!dirp) return;

while (!readdir_r(dirp, &dirent, &result) && result)
{
const std::string virtualName(result->d_name);
#endif
// check for "." and ".."
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
((virtualName[0] == '.') && (virtualName[1] == '.') &&
(virtualName[2] == '\0')))
if (virtualName == "." || virtualName == "..")
continue;

std::string source, dest;
Expand All @@ -580,6 +592,10 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
CopyDir(source, dest);
}
else if (!File::Exists(dest)) File::Copy(source, dest);
#ifdef _WIN32
} while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
#else
}
closedir(dirp);
#endif
Expand Down Expand Up @@ -643,9 +659,9 @@ std::string GetSysDirectory()
std::string sysDir;

#if defined (__APPLE__)
sysDir = GetBundleDirectory();
sysDir += DIR_SEP;
sysDir += SYSDATA_DIR;
sysDir = GetBundleDirectory() + DIR_SEP + SYSDATA_DIR;
#elif defined (_WIN32)
sysDir = GetExeDirectory() + DIR_SEP + SYSDATA_DIR;
#else
sysDir = SYSDATA_DIR;
#endif
Expand All @@ -665,7 +681,52 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
if (paths[D_USER_IDX].empty())
{
#ifdef _WIN32
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
// Detect where the User directory is. There are four different cases (on top of the
// command line flag, which overrides all this):
// 1. HKCU\Software\Dolphin Emulator\LocalUserConfig exists and is true
// -> Use GetExeDirectory()\User
// 2. HKCU\Software\Dolphin Emulator\UserConfigPath exists
// -> Use this as the user directory path
// 3. My Documents exists
// -> Use My Documents\Dolphin Emulator as the User directory path
// 4. Default
// -> Use GetExeDirectory()\User

// Check our registry keys
HKEY hkey;
DWORD local = 0;
TCHAR configPath[MAX_PATH] = {0};
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), NULL, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
{
DWORD size = 4;
if (RegQueryValueEx(hkey, TEXT("LocalUserConfig"), NULL, NULL, reinterpret_cast<LPBYTE>(&local), &size) != ERROR_SUCCESS)
local = 0;

size = MAX_PATH;
if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), NULL, NULL, (LPBYTE)configPath, &size) != ERROR_SUCCESS)
configPath[0] = 0;
RegCloseKey(hkey);
}

// Get Program Files path in case we need it.
TCHAR my_documents[MAX_PATH];
bool my_documents_found = SUCCEEDED(SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, my_documents));

if (local) // Case 1
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
else if (configPath[0]) // Case 2
paths[D_USER_IDX] = TStrToUTF8(configPath);
else if (my_documents_found) // Case 3
paths[D_USER_IDX] = TStrToUTF8(my_documents) + DIR_SEP "Dolphin Emulator" DIR_SEP;
else // Case 4
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;

// Prettify the path: it will be displayed in some places, we don't want a mix of \ and /.
paths[D_USER_IDX] = ReplaceAll(paths[D_USER_IDX], "\\", DIR_SEP);

// Make sure it ends in DIR_SEP.
if (*paths[D_USER_IDX].rbegin() != DIR_SEP_CHR)
paths[D_USER_IDX] += DIR_SEP;
#else
if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
Expand All @@ -679,7 +740,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
paths[D_WIIUSER_IDX] = paths[D_WIIROOT_IDX] + DIR_SEP;
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
paths[D_GAMESETTINGS_IDX] = paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP;
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
Expand Down Expand Up @@ -730,37 +791,37 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
break;

case D_USER_IDX:
paths[D_GCUSER_IDX] = paths[D_USER_IDX] + GC_USER_DIR DIR_SEP;
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
paths[D_WIIUSER_IDX] = paths[D_WIIROOT_IDX] + DIR_SEP;
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
paths[D_OPENCL_IDX] = paths[D_USER_IDX] + OPENCL_DIR DIR_SEP;
paths[D_HIRESTEXTURES_IDX] = paths[D_USER_IDX] + HIRES_TEXTURES_DIR DIR_SEP;
paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
paths[D_DUMPDSP_IDX] = paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP;
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
paths[D_MAILLOGS_IDX] = paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP;
paths[D_WIISYSCONF_IDX] = paths[D_WIIUSER_IDX] + WII_SYSCONF_DIR DIR_SEP;
paths[D_THEMES_IDX] = paths[D_USER_IDX] + THEMES_DIR DIR_SEP;
paths[F_DOLPHINCONFIG_IDX] = paths[D_CONFIG_IDX] + DOLPHIN_CONFIG;
paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
paths[F_WIISYSCONF_IDX] = paths[D_WIISYSCONF_IDX] + WII_SYSCONF;
paths[F_RAMDUMP_IDX] = paths[D_DUMP_IDX] + RAM_DUMP;
paths[F_ARAMDUMP_IDX] = paths[D_DUMP_IDX] + ARAM_DUMP;
paths[F_FAKEVMEMDUMP_IDX] = paths[D_DUMP_IDX] + FAKEVMEM_DUMP;
paths[F_GCSRAM_IDX] = paths[D_GCUSER_IDX] + GC_SRAM;
paths[D_GCUSER_IDX] = paths[D_USER_IDX] + GC_USER_DIR DIR_SEP;
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
paths[D_WIIUSER_IDX] = paths[D_WIIROOT_IDX] + DIR_SEP;
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
paths[D_GAMESETTINGS_IDX] = paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP;
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
paths[D_OPENCL_IDX] = paths[D_USER_IDX] + OPENCL_DIR DIR_SEP;
paths[D_HIRESTEXTURES_IDX] = paths[D_USER_IDX] + HIRES_TEXTURES_DIR DIR_SEP;
paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
paths[D_DUMPDSP_IDX] = paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP;
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
paths[D_MAILLOGS_IDX] = paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP;
paths[D_WIISYSCONF_IDX] = paths[D_WIIUSER_IDX] + WII_SYSCONF_DIR DIR_SEP;
paths[D_THEMES_IDX] = paths[D_USER_IDX] + THEMES_DIR DIR_SEP;
paths[F_DOLPHINCONFIG_IDX] = paths[D_CONFIG_IDX] + DOLPHIN_CONFIG;
paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
paths[F_WIISYSCONF_IDX] = paths[D_WIISYSCONF_IDX] + WII_SYSCONF;
paths[F_RAMDUMP_IDX] = paths[D_DUMP_IDX] + RAM_DUMP;
paths[F_ARAMDUMP_IDX] = paths[D_DUMP_IDX] + ARAM_DUMP;
paths[F_FAKEVMEMDUMP_IDX] = paths[D_DUMP_IDX] + FAKEVMEM_DUMP;
paths[F_GCSRAM_IDX] = paths[D_GCUSER_IDX] + GC_SRAM;
break;

case D_CONFIG_IDX:
Expand Down Expand Up @@ -800,12 +861,10 @@ std::string GetThemeDir(const std::string& theme_name)
{
std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/";

#if !defined(_WIN32)
// If theme does not exist in user's dir load from shared directory
if (!File::Exists(dir))
dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/";
#endif

dir = GetSysDirectory() + THEMES_DIR "/" + theme_name + "/";

return dir;
}

Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Common/Src/FileUtil.h
Expand Up @@ -21,8 +21,8 @@ enum {
D_GCUSER_IDX,
D_WIIROOT_IDX,
D_WIIUSER_IDX,
D_CONFIG_IDX,
D_GAMECONFIG_IDX,
D_CONFIG_IDX, // global settings
D_GAMESETTINGS_IDX, // user-specified settings which override both the global and the default settings (per game)
D_MAPS_IDX,
D_CACHE_IDX,
D_SHADERCACHE_IDX,
Expand Down
167 changes: 72 additions & 95 deletions Source/Core/Common/Src/IniFile.cpp
Expand Up @@ -20,7 +20,7 @@

namespace {

static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut)
void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut)
{
if (line[0] == '#')
return;
Expand All @@ -37,32 +37,15 @@ static void ParseLine(const std::string& line, std::string* keyOut, std::string*

}

std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut)
{
for (std::vector<std::string>::iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
std::string& line = *iter;
std::string lineKey;
ParseLine(line, &lineKey, valueOut);
if (!strcasecmp(lineKey.c_str(), key))
return &line;
}
return 0;
}

void IniFile::Section::Set(const char* key, const char* newValue)
{
std::string value;
std::string* line = GetLine(key, &value);
if (line)
{
// Change the value - keep the key and comment
*line = StripSpaces(key) + " = " + newValue;
}
auto it = values.find(key);
if (it != values.end())
it->second = newValue;
else
{
// The key did not already exist in this section - let's add it.
lines.push_back(std::string(key) + " = " + newValue);
values[key] = newValue;
keys_order.push_back(key);
}
}

Expand All @@ -74,20 +57,6 @@ void IniFile::Section::Set(const char* key, const std::string& newValue, const s
Delete(key);
}

bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue)
{
std::string* line = GetLine(key, value);
if (!line)
{
if (defaultValue)
{
*value = defaultValue;
}
return false;
}
return true;
}

void IniFile::Section::Set(const char* key, const float newValue, const float defaultValue)
{
if (newValue != defaultValue)
Expand Down Expand Up @@ -126,7 +95,24 @@ void IniFile::Section::Set(const char* key, const std::vector<std::string>& newV
Set(key, temp.c_str());
}

bool IniFile::Section::Get(const char* key, std::vector<std::string>& values)
bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue)
{
auto it = values.find(key);
if (it != values.end())
{
*value = it->second;
return true;
}
else if (defaultValue)
{
*value = defaultValue;
return true;
}
else
return false;
}

bool IniFile::Section::Get(const char* key, std::vector<std::string>& out)
{
std::string temp;
bool retval = Get(key, &temp, 0);
Expand All @@ -145,7 +131,7 @@ bool IniFile::Section::Get(const char* key, std::vector<std::string>& values)
subEnd = temp.find_first_of(",", subStart);
if (subStart != subEnd)
// take from first char until next ,
values.push_back(StripSpaces(temp.substr(subStart, subEnd - subStart)));
out.push_back(StripSpaces(temp.substr(subStart, subEnd - subStart)));

// Find the next non , char
subStart = temp.find_first_not_of(",", subEnd);
Expand Down Expand Up @@ -206,28 +192,18 @@ bool IniFile::Section::Get(const char* key, double* value, double defaultValue)

bool IniFile::Section::Exists(const char *key) const
{
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
std::string lineKey;
ParseLine(*iter, &lineKey, NULL);
if (!strcasecmp(lineKey.c_str(), key))
return true;
}
return false;
return values.find(key) != values.end();
}

bool IniFile::Section::Delete(const char *key)
{
std::string* line = GetLine(key, 0);
for (std::vector<std::string>::iterator liter = lines.begin(); liter != lines.end(); ++liter)
{
if (line == &*liter)
{
lines.erase(liter);
return true;
}
}
return false;
auto it = values.find(key);
if (it == values.end())
return false;

values.erase(it);
keys_order.erase(std::find(keys_order.begin(), keys_order.end(), key));
return true;
}

// IniFile
Expand Down Expand Up @@ -286,28 +262,15 @@ bool IniFile::Exists(const char* sectionName, const char* key) const
void IniFile::SetLines(const char* sectionName, const std::vector<std::string> &lines)
{
Section* section = GetOrCreateSection(sectionName);
section->lines.clear();
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
section->lines.push_back(*iter);
}
section->lines = lines;
}

bool IniFile::DeleteKey(const char* sectionName, const char* key)
{
Section* section = GetSection(sectionName);
if (!section)
return false;
std::string* line = section->GetLine(key, 0);
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
if (line == &(*liter))
{
section->lines.erase(liter);
return true;
}
}
return false; //shouldn't happen
return section->Delete(key);
}

// Return a list of all keys in a section
Expand All @@ -316,13 +279,7 @@ bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) c
const Section* section = GetSection(sectionName);
if (!section)
return false;
keys.clear();
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
std::string key;
ParseLine(*liter, &key, 0);
keys.push_back(key);
}
keys = section->keys_order;
return true;
}

Expand Down Expand Up @@ -364,13 +321,13 @@ void IniFile::SortSections()
std::sort(sections.begin(), sections.end());
}

bool IniFile::Load(const char* filename)
bool IniFile::Load(const char* filename, bool keep_current_data)
{
// Maximum number of letters in a line
static const int MAX_BYTES = 1024*32;

sections.clear();
sections.push_back(Section(""));
if (!keep_current_data)
sections.clear();
// first section consists of the comments before the first real section

// Open file
Expand All @@ -379,12 +336,13 @@ bool IniFile::Load(const char* filename)

if (in.fail()) return false;

Section* current_section = NULL;
while (!in.eof())
{
char templine[MAX_BYTES];
in.getline(templine, MAX_BYTES);
std::string line = templine;

#ifndef _WIN32
// Check for CRLF eol and convert it to LF
if (!line.empty() && line.at(line.size()-1) == '\r')
Expand All @@ -405,12 +363,25 @@ bool IniFile::Load(const char* filename)
{
// New section!
std::string sub = line.substr(1, endpos - 1);
sections.push_back(Section(sub));
current_section = GetOrCreateSection(sub.c_str());
}
}
else
{
sections[sections.size() - 1].lines.push_back(line);
if (current_section)
{
std::string key, value;
ParseLine(line, &key, &value);

// Lines starting with '$' or '+' are kept verbatim. Kind
// of a hack, but the support for raw lines inside an INI
// is a hack anyway.
if ((key == "" && value == "")
|| (line.size() >= 1 && (line[0] == '$' || line[0] == '+')))
current_section->lines.push_back(line.c_str());
else
current_section->Set(key, value.c_str());
}
}
}
}
Expand All @@ -429,27 +400,33 @@ bool IniFile::Save(const char* filename)
return false;
}

// Currently testing if dolphin community can handle the requirements of C++11 compilation
// If you get a compiler error on this line, your compiler is probably old.
// Update to g++ 4.4 or a recent version of clang (XCode 4.2 on OS X).
// If you don't want to update, complain in a google code issue, the dolphin forums or #dolphin-emu.
for (auto iter = sections.begin(); iter != sections.end(); ++iter)
{
const Section& section = *iter;

if (section.name != "")
{
if (section.keys_order.size() != 0 || section.lines.size() != 0)
out << "[" << section.name << "]" << std::endl;
}

for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)
if (section.keys_order.size() == 0)
{
for (auto liter = section.lines.begin(); liter != section.lines.end(); ++liter)
{
std::string s = *liter;
out << s << std::endl;
}
}
else
{
std::string s = *liter;
out << s << std::endl;
for (auto kvit = section.keys_order.begin(); kvit != section.keys_order.end(); ++kvit)
{
auto pair = section.values.find(*kvit);
out << pair->first << " = " << pair->second << std::endl;
}
}
}

out.close();

return true;
}

Expand Down
29 changes: 25 additions & 4 deletions Source/Core/Common/Src/IniFile.h
Expand Up @@ -6,11 +6,21 @@
#ifndef _INIFILE_H_
#define _INIFILE_H_

#include <map>
#include <string>
#include <set>
#include <vector>

#include "StringUtil.h"

struct CaseInsensitiveStringCompare
{
bool operator() (const std::string& a, const std::string& b) const
{
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
};

class IniFile
{
public:
Expand All @@ -25,7 +35,6 @@ class IniFile
bool Exists(const char *key) const;
bool Delete(const char *key);

std::string* GetLine(const char* key, std::string* valueOut);
void Set(const char* key, const char* newValue);
void Set(const char* key, const std::string& newValue, const std::string& defaultValue);

Expand Down Expand Up @@ -68,12 +77,24 @@ class IniFile
}

protected:
std::vector<std::string> lines;
std::string name;

std::vector<std::string> keys_order;
std::map<std::string, std::string, CaseInsensitiveStringCompare> values;

std::vector<std::string> lines;
};

bool Load(const char* filename);
bool Load(const std::string &filename) { return Load(filename.c_str()); }
/**
* Loads sections and keys.
* @param filename filename of the ini file which should be loaded
* @param keep_current_data If true, "extends" the currently loaded list of sections and keys with the loaded data (and replaces existing entries). If false, existing data will be erased.
* @warning Using any other operations than "Get*" and "Exists" is untested and will behave unexpectedly
* @todo This really is just a hack to support having two levels of gameinis (defaults and user-specified) and should eventually be replaced with a less stupid system.
*/
bool Load(const char* filename, bool keep_current_data = false);
bool Load(const std::string &filename, bool keep_current_data = false) { return Load(filename.c_str(), keep_current_data); }

bool Save(const char* filename);
bool Save(const std::string &filename) { return Save(filename.c_str()); }

Expand Down
154 changes: 80 additions & 74 deletions Source/Core/Core/Src/ActionReplay.cpp
Expand Up @@ -111,115 +111,121 @@ bool CompareValues(const u32 val1, const u32 val2, const int type);

// ----------------------
// AR Remote Functions
void LoadCodes(IniFile &ini, bool forceLoad)
void LoadCodes(IniFile &globalIni, IniFile &localIni, bool forceLoad)
{
// Parses the Action Replay section of a game ini file.
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats
&& !forceLoad)
return;

std::vector<std::string> lines;
std::vector<std::string> encryptedLines;
ARCode currentCode;
arCodes.clear();

if (!ini.GetLines("ActionReplay", lines))
return; // no codes found.
std::vector<std::string> enabledLines;
std::set<std::string> enabledNames;
localIni.GetLines("ActionReplay_Enabled", enabledLines);
for (auto iter = enabledLines.begin(); iter != enabledLines.end(); ++iter)
{
const std::string& line = *iter;
if (line.size() != 0 && line[0] == '$')
{
std::string name = line.substr(1, line.size() - 1);
enabledNames.insert(name);
}
}

std::vector<std::string>::const_iterator
it = lines.begin(),
lines_end = lines.end();
for (; it != lines_end; ++it)
IniFile* inis[] = {&globalIni, &localIni};
for (size_t i = 0; i < ArraySize(inis); ++i)
{
const std::string line = *it;
std::vector<std::string> lines;
std::vector<std::string> encryptedLines;
ARCode currentCode;

if (line.empty())
continue;
inis[i]->GetLines("ActionReplay", lines);

std::vector<std::string> pieces;

// Check if the line is a name of the code
if (line[0] == '+' || line[0] == '$')
std::vector<std::string>::const_iterator
it = lines.begin(),
lines_end = lines.end();
for (; it != lines_end; ++it)
{
if (currentCode.ops.size())
const std::string line = *it;

if (line.empty())
continue;

std::vector<std::string> pieces;

// Check if the line is a name of the code
if (line[0] == '$')
{
arCodes.push_back(currentCode);
currentCode.ops.clear();
if (currentCode.ops.size())
{
arCodes.push_back(currentCode);
currentCode.ops.clear();
}
if (encryptedLines.size())
{
DecryptARCode(encryptedLines, currentCode.ops);
arCodes.push_back(currentCode);
currentCode.ops.clear();
encryptedLines.clear();
}

currentCode.name = line.substr(1, line.size() - 1);
currentCode.active = enabledNames.find(currentCode.name) != enabledNames.end();
currentCode.user_defined = (i == 1);
}
if (encryptedLines.size())
else
{
DecryptARCode(encryptedLines, currentCode.ops);
arCodes.push_back(currentCode);
currentCode.ops.clear();
encryptedLines.clear();
}
SplitString(line, ' ', pieces);

if (line.size() > 1)
{
if (line[0] == '+')
// Check if the AR code is decrypted
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
{
currentCode.active = true;
currentCode.name = line.substr(2, line.size() - 2);;
if (!forceLoad)
Core::DisplayMessage("AR code active: " + currentCode.name, 5000);
AREntry op;
bool success_addr = TryParse(std::string("0x") + pieces[0], &op.cmd_addr);
bool success_val = TryParse(std::string("0x") + pieces[1], &op.value);
if (!(success_addr | success_val)) {
PanicAlertT("Action Replay Error: invalid AR code line: %s", line.c_str());
if (!success_addr) PanicAlertT("The address is invalid");
if (!success_val) PanicAlertT("The value is invalid");
}
else
{
currentCode.ops.push_back(op);
}
}
else
{
currentCode.active = false;
currentCode.name = line.substr(1, line.size() - 1);
SplitString(line, '-', pieces);
if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && pieces[2].size() == 5)
{
// Encrypted AR code
// Decryption is done in "blocks", so we must push blocks into a vector,
// then send to decrypt when a new block is encountered, or if it's the last block.
encryptedLines.push_back(pieces[0]+pieces[1]+pieces[2]);
}
}
}
continue;
}

SplitString(line, ' ', pieces);

// Check if the AR code is decrypted
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
// Handle the last code correctly.
if (currentCode.ops.size())
{
AREntry op;
bool success_addr = TryParse(std::string("0x") + pieces[0], &op.cmd_addr);
bool success_val = TryParse(std::string("0x") + pieces[1], &op.value);
if (!(success_addr | success_val)) {
PanicAlertT("Action Replay Error: invalid AR code line: %s", line.c_str());
if (!success_addr) PanicAlertT("The address is invalid");
if (!success_val) PanicAlertT("The value is invalid");
}
else
{
currentCode.ops.push_back(op);
}
arCodes.push_back(currentCode);
}
else
if (encryptedLines.size())
{
SplitString(line, '-', pieces);
if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && pieces[2].size() == 5)
{
// Encrypted AR code
// Decryption is done in "blocks", so we must push blocks into a vector,
// then send to decrypt when a new block is encountered, or if it's the last block.
encryptedLines.push_back(pieces[0]+pieces[1]+pieces[2]);
}
DecryptARCode(encryptedLines, currentCode.ops);
arCodes.push_back(currentCode);
}
}

// Handle the last code correctly.
if (currentCode.ops.size())
{
arCodes.push_back(currentCode);
}
if (encryptedLines.size())
{
DecryptARCode(encryptedLines, currentCode.ops);
arCodes.push_back(currentCode);
}

UpdateActiveList();
}

void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &ini)
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &globalIni, IniFile& localIni)
{
LoadCodes(ini, true);
LoadCodes(globalIni, localIni, true);
_arCodes = arCodes;
}

Expand Down
5 changes: 3 additions & 2 deletions Source/Core/Core/Src/ActionReplay.h
Expand Up @@ -23,12 +23,13 @@ struct ARCode
std::string name;
std::vector<AREntry> ops;
bool active;
bool user_defined;
};

void RunAllActive();
bool RunCode(const ARCode &arcode);
void LoadCodes(IniFile &ini, bool forceLoad);
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &ini);
void LoadCodes(IniFile &globalIni, IniFile &localIni, bool forceLoad);
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &globalIni, IniFile &localIni);
size_t GetCodeListSize();
ARCode GetARCode(size_t index);
void SetARCode_IsActive(bool active, size_t index);
Expand Down
80 changes: 45 additions & 35 deletions Source/Core/Core/Src/Boot/Boot.cpp
Expand Up @@ -71,59 +71,73 @@ void CBoot::UpdateDebugger_MapLoaded(const char *_gameID)
Host_NotifyMapLoaded();
}

std::string CBoot::GenerateMapFilename()
bool CBoot::FindMapFile(std::string* existing_map_file,
std::string* writable_map_file)
{
std::string title_id_str;

SCoreStartupParameter& _StartupPara = SConfig::GetInstance().m_LocalCoreStartupParameter;
switch (_StartupPara.m_BootType)
{
case SCoreStartupParameter::BOOT_WII_NAND:
{
const DiscIO::INANDContentLoader& Loader = DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename);
const DiscIO::INANDContentLoader& Loader =
DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename);
if (Loader.IsValid())
{
u64 TitleID = Loader.GetTitleID();
char tmpBuffer[32];
sprintf(tmpBuffer, "%08x_%08x", (u32)(TitleID >> 32) & 0xFFFFFFFF , (u32)TitleID & 0xFFFFFFFF );
return File::GetUserPath(D_MAPS_IDX) + std::string(tmpBuffer) + ".map";
title_id_str = StringFromFormat("%08X_%08X",
(u32)(TitleID >> 32) & 0xFFFFFFFF,
(u32)TitleID & 0xFFFFFFFF);
}
break;
}

case SCoreStartupParameter::BOOT_ELF:
case SCoreStartupParameter::BOOT_DOL:
return _StartupPara.m_strFilename.substr(0, _StartupPara.m_strFilename.size()-4) + ".map";
// Strip the .elf/.dol file extension
title_id_str = _StartupPara.m_strFilename.substr(
0, _StartupPara.m_strFilename.size() - 4);
break;

default:
return File::GetUserPath(D_MAPS_IDX) + _StartupPara.GetUniqueID() + ".map";
title_id_str = _StartupPara.GetUniqueID();
break;
}

return std::string("unknown map");
}

bool CBoot::LoadMapFromFilename(const std::string &_rFilename, const char *_gameID)
{
if (_rFilename.size() == 0)
return false;

std::string strMapFilename = GenerateMapFilename();
if (writable_map_file)
*writable_map_file = File::GetUserPath(D_MAPS_IDX) + title_id_str + ".map";

bool success = false;
if (!g_symbolDB.LoadMap(strMapFilename.c_str()))
bool found = false;
static const std::string maps_directories[] = {
File::GetUserPath(D_MAPS_IDX),
File::GetSysDirectory() + MAPS_DIR DIR_SEP
};
for (size_t i = 0; !found && i < ArraySize(maps_directories); ++i)
{
if (_gameID != NULL)
std::string path = maps_directories[i] + title_id_str + ".map";
if (File::Exists(path))
{
BuildCompleteFilename(strMapFilename, "maps", std::string(_gameID) + ".map");
success = g_symbolDB.LoadMap(strMapFilename.c_str());
found = true;
if (existing_map_file)
*existing_map_file = path;
}
}
else
{
success = true;
}

if (success)
return found;
}

bool CBoot::LoadMapFromFilename()
{
std::string strMapFilename;
bool found = FindMapFile(&strMapFilename, NULL);
if (found && g_symbolDB.LoadMap(strMapFilename.c_str()))
{
UpdateDebugger_MapLoaded();
return true;
}

return success;
return false;
}

// If ipl.bin is not found, this function does *some* of what BS1 does:
Expand Down Expand Up @@ -201,10 +215,6 @@ bool CBoot::BootUp()
PanicAlertT("Warning - starting ISO in wrong console mode!");
}

char gameID[7];
memcpy(gameID, pVolume->GetUniqueID().c_str(), 6);
gameID[6] = 0;

// setup the map from ISOFile ID
VolumeHandler::SetVolumeName(_StartupPara.m_strFilename);

Expand Down Expand Up @@ -252,7 +262,7 @@ bool CBoot::BootUp()

/* Try to load the symbol map if there is one, and then scan it for
and eventually replace code */
if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID))
if (LoadMapFromFilename())
HLE::PatchFunctions();

// We don't need the volume any more
Expand Down Expand Up @@ -298,7 +308,7 @@ bool CBoot::BootUp()
PC = dolLoader.GetEntryPoint();
}

if (LoadMapFromFilename(_StartupPara.m_strFilename))
if (LoadMapFromFilename())
HLE::PatchFunctions();

break;
Expand Down Expand Up @@ -368,7 +378,7 @@ bool CBoot::BootUp()
case SCoreStartupParameter::BOOT_WII_NAND:
Boot_WiiWAD(_StartupPara.m_strFilename.c_str());

if (LoadMapFromFilename(_StartupPara.m_strFilename))
if (LoadMapFromFilename())
HLE::PatchFunctions();

// load default image or create virtual drive from directory
Expand All @@ -387,7 +397,7 @@ bool CBoot::BootUp()
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
if (Load_BS2(_StartupPara.m_strBootROM))
{
if (LoadMapFromFilename(_StartupPara.m_strFilename))
if (LoadMapFromFilename())
HLE::PatchFunctions();
}
else
Expand Down
16 changes: 14 additions & 2 deletions Source/Core/Core/Src/Boot/Boot.h
Expand Up @@ -16,14 +16,26 @@ class CBoot

static bool BootUp();
static bool IsElfWii(const char *filename);
static std::string GenerateMapFilename();

// Tries to find a map file for the current game by looking first in the
// local user directory, then in the shared user directory.
//
// If existing_map_file is not NULL and a map file exists, it is set to the
// path to the existing map file.
//
// If writable_map_file is not NULL, it is set to the path to where a map
// file should be saved.
//
// Returns true if a map file exists, false if none could be found.
static bool FindMapFile(std::string* existing_map_file,
std::string* writable_map_file);

private:
static void RunFunction(u32 _iAddr);

static void UpdateDebugger_MapLoaded(const char* _gameID = NULL);

static bool LoadMapFromFilename(const std::string& _rFilename, const char* _gameID = NULL);
static bool LoadMapFromFilename();
static bool Boot_ELF(const char *filename);
static bool Boot_WiiWAD(const char *filename);

Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/Boot/Boot_ELF.cpp
Expand Up @@ -68,7 +68,7 @@ bool CBoot::Boot_ELF(const char *filename)
reader.LoadInto(0x80000000);
if (!reader.LoadSymbols())
{
if (LoadMapFromFilename(filename))
if (LoadMapFromFilename())
HLE::PatchFunctions();
}
else
Expand Down
12 changes: 9 additions & 3 deletions Source/Core/Core/Src/BootManager.cpp
Expand Up @@ -24,6 +24,7 @@
#include <vector>

#include "Common.h"
#include "CommonPaths.h"
#include "IniFile.h"
#include "BootManager.h"
#include "Volume.h"
Expand Down Expand Up @@ -73,11 +74,16 @@ bool BootCore(const std::string& _rFilename)
return false;

// Load game specific settings
IniFile game_ini;
std::string unique_id = StartUp.GetUniqueID();
StartUp.m_strGameIni = File::GetUserPath(D_GAMECONFIG_IDX) + unique_id + ".ini";
if (unique_id.size() == 6 && game_ini.Load(StartUp.m_strGameIni.c_str()))
StartUp.m_strGameIniDefault = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + unique_id + ".ini";
StartUp.m_strGameIniLocal = File::GetUserPath(D_GAMESETTINGS_IDX) + unique_id + ".ini";

if (unique_id.size() == 6)
{
IniFile game_ini;
game_ini.Load(StartUp.m_strGameIniDefault);
game_ini.Load(StartUp.m_strGameIniLocal, true);

config_cache.valid = true;
config_cache.bCPUThread = StartUp.bCPUThread;
config_cache.bSkipIdle = StartUp.bSkipIdle;
Expand Down
12 changes: 6 additions & 6 deletions Source/Core/Core/Src/ConfigManager.cpp
Expand Up @@ -167,7 +167,7 @@ void SConfig::SaveSettings()
}

ini.Set("General", "RecursiveGCMPaths", m_RecursiveISOFolder);
ini.Set("General", "NANDRoot", m_NANDPath);
ini.Set("General", "NANDRootPath", m_NANDPath);
ini.Set("General", "WirelessMac", m_WirelessMac);
#ifdef USE_GDBSTUB
ini.Set("General", "GDBPort", m_LocalCoreStartupParameter.iGDBPort);
Expand Down Expand Up @@ -244,8 +244,8 @@ void SConfig::SaveSettings()
ini.Set("Core", "SelectedLanguage", m_LocalCoreStartupParameter.SelectedLanguage);
ini.Set("Core", "DPL2Decoder", m_LocalCoreStartupParameter.bDPL2Decoder);
ini.Set("Core", "Latency", m_LocalCoreStartupParameter.iLatency);
ini.Set("Core", "MemcardA", m_strMemoryCardA);
ini.Set("Core", "MemcardB", m_strMemoryCardB);
ini.Set("Core", "MemcardAPath", m_strMemoryCardA);
ini.Set("Core", "MemcardBPath", m_strMemoryCardB);
ini.Set("Core", "SlotA", m_EXIDevice[0]);
ini.Set("Core", "SlotB", m_EXIDevice[1]);
ini.Set("Core", "SerialPort1", m_EXIDevice[2]);
Expand Down Expand Up @@ -318,7 +318,7 @@ void SConfig::LoadSettings()

ini.Get("General", "RecursiveGCMPaths", &m_RecursiveISOFolder, false);

ini.Get("General", "NANDRoot", &m_NANDPath);
ini.Get("General", "NANDRootPath", &m_NANDPath);
m_NANDPath = File::GetUserPath(D_WIIROOT_IDX, m_NANDPath);
DiscIO::cUIDsys::AccessInstance().UpdateLocation();
DiscIO::CSharedContent::AccessInstance().UpdateLocation();
Expand Down Expand Up @@ -403,8 +403,8 @@ void SConfig::LoadSettings()
ini.Get("Core", "SelectedLanguage", &m_LocalCoreStartupParameter.SelectedLanguage, 0);
ini.Get("Core", "DPL2Decoder", &m_LocalCoreStartupParameter.bDPL2Decoder, false);
ini.Get("Core", "Latency", &m_LocalCoreStartupParameter.iLatency, 2);
ini.Get("Core", "MemcardA", &m_strMemoryCardA);
ini.Get("Core", "MemcardB", &m_strMemoryCardB);
ini.Get("Core", "MemcardAPath", &m_strMemoryCardA);
ini.Get("Core", "MemcardBPath", &m_strMemoryCardB);
ini.Get("Core", "SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD);
ini.Get("Core", "SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE);
ini.Get("Core", "SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE);
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/Core/Src/Core.cpp
Expand Up @@ -205,7 +205,8 @@ bool Init()
if (g_aspect_wide)
{
IniFile gameIni;
gameIni.Load(_CoreParameter.m_strGameIni.c_str());
gameIni.Load(_CoreParameter.m_strGameIniDefault.c_str());
gameIni.Load(_CoreParameter.m_strGameIniLocal.c_str(), true);
gameIni.Get("Wii", "Widescreen", &g_aspect_wide,
!!SConfig::GetInstance().m_SYSCONF->
GetData<u8>("IPL.AR"));
Expand Down
6 changes: 1 addition & 5 deletions Source/Core/Core/Src/CoreParameter.cpp
Expand Up @@ -351,11 +351,7 @@ void SCoreStartupParameter::CheckMemcardPath(std::string& memcardPath, std::stri
{
// Use default memcard path if there is no user defined name
std::string defaultFilename = isSlotA ? GC_MEMCARDA : GC_MEMCARDB;
#ifdef _WIN32
memcardPath = "." + File::GetUserPath(D_GCUSER_IDX).substr(File::GetExeDirectory().size()) + defaultFilename + ext;
#else
memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext;
#endif
memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext;
}
else
{
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/Core/Src/CoreParameter.h
Expand Up @@ -198,7 +198,8 @@ struct SCoreStartupParameter
std::string m_strApploader;
std::string m_strUniqueID;
std::string m_strName;
std::string m_strGameIni;
std::string m_strGameIniDefault;
std::string m_strGameIniLocal;

// Constructor just calls LoadDefaults
SCoreStartupParameter();
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/Core/Src/GeckoCodeConfig.cpp
Expand Up @@ -15,6 +15,7 @@
namespace Gecko
{

// TODO: Support loading codes from default game inis.
void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
{
std::vector<std::string> lines;
Expand Down Expand Up @@ -96,7 +97,7 @@ void SaveGeckoCode(std::vector<std::string>& lines, const GeckoCode& gcode)
}

lines.push_back(name);

// save all the code lines
std::vector<GeckoCode::Code>::const_iterator
codes_iter = gcode.codes.begin(),
Expand Down
122 changes: 71 additions & 51 deletions Source/Core/Core/Src/PatchEngine.cpp
Expand Up @@ -20,6 +20,7 @@
#include <map>
#include <algorithm>

#include "CommonPaths.h"
#include "StringUtil.h"
#include "PatchEngine.h"
#include "HW/Memmap.h"
Expand All @@ -44,62 +45,79 @@ std::vector<Patch> onFrame;
std::map<u32, int> speedHacks;
std::vector<std::string> discList;

void LoadPatchSection(const char *section, std::vector<Patch> &patches, IniFile &ini)
void LoadPatchSection(const char *section, std::vector<Patch> &patches,
IniFile &globalIni, IniFile &localIni)
{
std::vector<std::string> lines;

if (!ini.GetLines(section, lines))
return;
// Load the name of all enabled patches
std::string enabledSectionName = std::string(section) + "_Enabled";
std::vector<std::string> enabledLines;
std::set<std::string> enabledNames;
localIni.GetLines(enabledSectionName.c_str(), enabledLines);
for (auto iter = enabledLines.begin(); iter != enabledLines.end(); ++iter)
{
const std::string& line = *iter;
if (line.size() != 0 && line[0] == '$')
{
std::string name = line.substr(1, line.size() - 1);
enabledNames.insert(name);
}
}

Patch currentPatch;
IniFile* inis[] = {&globalIni, &localIni};

for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
for (size_t i = 0; i < ArraySize(inis); ++i)
{
std::string line = *iter;
std::vector<std::string> lines;
Patch currentPatch;
inis[i]->GetLines(section, lines);

if (line.size())
for (auto iter = lines.begin(); iter != lines.end(); ++iter)
{
if (line[0] == '+' || line[0] == '$')
std::string line = *iter;

if (line.size() == 0)
continue;

if (line[0] == '$')
{
// Take care of the previous code
if (currentPatch.name.size())
patches.push_back(currentPatch);
currentPatch.entries.clear();

// Set active and name
currentPatch.active = (line[0] == '+') ? true : false;
if (currentPatch.active)
currentPatch.name = line.substr(2, line.size() - 2);
else
currentPatch.name = line.substr(1, line.size() - 1);
continue;
currentPatch.name = line.substr(1, line.size() - 1);
currentPatch.active = enabledNames.find(currentPatch.name) != enabledNames.end();
currentPatch.user_defined = (i == 1);
}
else
{
std::string::size_type loc = line.find_first_of('=', 0);

std::string::size_type loc = line.find_first_of('=', 0);

if (loc != std::string::npos)
line[loc] = ':';
if (loc != std::string::npos)
line[loc] = ':';

std::vector<std::string> items;
SplitString(line, ':', items);
std::vector<std::string> items;
SplitString(line, ':', items);

if (items.size() >= 3)
{
PatchEntry pE;
bool success = true;
success &= TryParse(items[0], &pE.address);
success &= TryParse(items[2], &pE.value);

pE.type = PatchType(std::find(PatchTypeStrings, PatchTypeStrings + 3, items[1]) - PatchTypeStrings);
success &= (pE.type != (PatchType)3);
if (success)
currentPatch.entries.push_back(pE);
if (items.size() >= 3)
{
PatchEntry pE;
bool success = true;
success &= TryParse(items[0], &pE.address);
success &= TryParse(items[2], &pE.value);

pE.type = PatchType(std::find(PatchTypeStrings, PatchTypeStrings + 3, items[1]) - PatchTypeStrings);
success &= (pE.type != (PatchType)3);
if (success)
currentPatch.entries.push_back(pE);
}
}
}
}

if (currentPatch.name.size() && currentPatch.entries.size())
patches.push_back(currentPatch);
if (currentPatch.name.size() && currentPatch.entries.size())
patches.push_back(currentPatch);
}
}

static void LoadDiscList(const char *section, std::vector<std::string> &_discList, IniFile &ini)
Expand Down Expand Up @@ -150,22 +168,24 @@ int GetSpeedhackCycles(const u32 addr)

void LoadPatches(const char *gameID)
{
IniFile ini;
std::string filename = File::GetUserPath(D_GAMECONFIG_IDX) + gameID + ".ini";
IniFile globalIni, localIni;
globalIni.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + gameID + ".ini");
localIni.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + gameID + ".ini", true);

if (ini.Load(filename.c_str()))
{
LoadPatchSection("OnFrame", onFrame, ini);
ActionReplay::LoadCodes(ini, false);

// lil silly
std::vector<Gecko::GeckoCode> gcodes;
Gecko::LoadCodes(ini, gcodes);
Gecko::SetActiveCodes(gcodes);

LoadSpeedhacks("Speedhacks", speedHacks, ini);
LoadDiscList("DiscList", discList, ini);
}
IniFile merged;
merged.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + gameID + ".ini");
merged.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + gameID + ".ini", true);

LoadPatchSection("OnFrame", onFrame, globalIni, localIni);
ActionReplay::LoadCodes(globalIni, localIni, false);

// lil silly
std::vector<Gecko::GeckoCode> gcodes;
Gecko::LoadCodes(localIni, gcodes);
Gecko::SetActiveCodes(gcodes);

LoadSpeedhacks("Speedhacks", speedHacks, merged);
LoadDiscList("DiscList", discList, merged);
}

void ApplyPatches(const std::vector<Patch> &patches)
Expand Down
4 changes: 3 additions & 1 deletion Source/Core/Core/Src/PatchEngine.h
Expand Up @@ -33,10 +33,12 @@ struct Patch
std::string name;
std::vector<PatchEntry> entries;
bool active;
bool user_defined; // False if this code is shipped with Dolphin.
};

int GetSpeedhackCycles(const u32 addr);
void LoadPatchSection(const char *section, std::vector<Patch> &patches, IniFile &ini);
void LoadPatchSection(const char *section, std::vector<Patch> &patches,
IniFile &globalIni, IniFile &localIni);
void LoadPatches(const char *gameID);
void ApplyFramePatches();
void ApplyARPatches();
Expand Down
9 changes: 3 additions & 6 deletions Source/Core/DolphinWX/CMakeLists.txt
Expand Up @@ -212,9 +212,6 @@ if(ANDROID)
add_custom_command(TARGET ${DOLPHIN_EXE} POST_BUILD
COMMAND cp ARGS ${CMAKE_SOURCE_DIR}/Data/Sys/GC/* ${CMAKE_SOURCE_DIR}/Source/Android/assets/
)
add_custom_command(TARGET ${DOLPHIN_EXE} POST_BUILD
COMMAND cp ARGS ${CMAKE_SOURCE_DIR}/Data/Sys/Wii/* ${CMAKE_SOURCE_DIR}/Source/Android/assets/
)
else()
add_executable(${DOLPHIN_EXE} ${SRCS})
target_link_libraries(${DOLPHIN_EXE} ${LIBS} ${WXLIBS})
Expand Down Expand Up @@ -247,14 +244,14 @@ else()

# Copy data files into application bundle.
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/copy_data_into_bundle.cmake "
file(INSTALL ${CMAKE_SOURCE_DIR}/Data/Sys ${CMAKE_SOURCE_DIR}/Data/User
file(INSTALL ${CMAKE_SOURCE_DIR}/Data/Sys
DESTINATION ${BUNDLE_PATH}/Contents/Resources
)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/did_copy_data_into_bundle \"\")
")
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/did_copy_data_into_bundle
COMMAND ${CMAKE_COMMAND} -P copy_data_into_bundle.cmake
DEPENDS ${CMAKE_SOURCE_DIR}/Data/Sys ${CMAKE_SOURCE_DIR}/Data/User
DEPENDS ${CMAKE_SOURCE_DIR}/Data/Sys
VERBATIM
)
add_custom_target(CopyDataIntoBundle ALL
Expand Down Expand Up @@ -291,7 +288,7 @@ else()
add_custom_command(OUTPUT ${BUNDLE_PATH}/Contents/Resources/en.lproj
COMMAND ${CMAKE_COMMAND} -P copy_translations_into_bundle.cmake
DEPENDS ${GMO_FILES}
${CMAKE_SOURCE_DIR}/Data/Sys ${CMAKE_SOURCE_DIR}/Data/User
${CMAKE_SOURCE_DIR}/Data/Sys
VERBATIM
)
add_custom_target(CopyTranslationsIntoBundle ALL
Expand Down
15 changes: 9 additions & 6 deletions Source/Core/DolphinWX/Src/CheatsWindow.cpp
Expand Up @@ -5,6 +5,7 @@
#include "Globals.h"
#include "CheatsWindow.h"
#include "ActionReplay.h"
#include "CommonPaths.h"
#include "Core.h"
#include "ConfigManager.h"
#include "VolumeHandler.h"
Expand Down Expand Up @@ -243,8 +244,10 @@ void wxCheatsWindow::OnEvent_Close(wxCloseEvent& ev)
void wxCheatsWindow::UpdateGUI()
{
// load code
m_gameini_path = File::GetUserPath(D_GAMECONFIG_IDX) + Core::g_CoreStartupParameter.GetUniqueID() + ".ini";
m_gameini.Load(m_gameini_path);
m_gameini_default_path = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + Core::g_CoreStartupParameter.GetUniqueID() + ".ini";
m_gameini_default.Load(m_gameini_default_path);
m_gameini_local_path = File::GetUserPath(D_GAMESETTINGS_IDX) + Core::g_CoreStartupParameter.GetUniqueID() + ".ini";
m_gameini_local.Load(m_gameini_local_path, true);
Load_ARCodes();
Load_GeckoCodes();

Expand Down Expand Up @@ -283,7 +286,7 @@ void wxCheatsWindow::Load_ARCodes()

void wxCheatsWindow::Load_GeckoCodes()
{
m_geckocode_panel->LoadCodes(m_gameini, Core::g_CoreStartupParameter.GetUniqueID(), true);
m_geckocode_panel->LoadCodes(m_gameini_local, Core::g_CoreStartupParameter.GetUniqueID(), true);
}

void wxCheatsWindow::OnEvent_CheatsList_ItemSelected(wxCommandEvent& WXUNUSED (event))
Expand Down Expand Up @@ -338,10 +341,10 @@ void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& ev)
Gecko::SetActiveCodes(m_geckocode_panel->GetCodes());

// Save gameini, with changed gecko codes
if (m_gameini_path.size())
if (m_gameini_local_path.size())
{
Gecko::SaveCodes(m_gameini, m_geckocode_panel->GetCodes());
m_gameini.Save(m_gameini_path);
Gecko::SaveCodes(m_gameini_local, m_geckocode_panel->GetCodes());
m_gameini_local.Save(m_gameini_local_path);
}

ev.Skip();
Expand Down
6 changes: 4 additions & 2 deletions Source/Core/DolphinWX/Src/CheatsWindow.h
Expand Up @@ -130,8 +130,10 @@ class wxCheatsWindow : public wxDialog
std::vector<ARCodeIndex> indexList;

Gecko::CodeConfigPanel *m_geckocode_panel;
IniFile m_gameini;
std::string m_gameini_path;
IniFile m_gameini_default;
IniFile m_gameini_local;
std::string m_gameini_default_path;
std::string m_gameini_local_path;

void Init_ChildControls();

Expand Down
4 changes: 1 addition & 3 deletions Source/Core/DolphinWX/Src/ConfigMain.cpp
Expand Up @@ -598,9 +598,7 @@ void CConfigMain::CreateGUIControls()

CFileSearch::XStringVector theme_dirs;
theme_dirs.push_back(File::GetUserPath(D_THEMES_IDX));
#if !defined(_WIN32)
theme_dirs.push_back(SHARED_USER_DIR THEMES_DIR);
#endif
theme_dirs.push_back(File::GetSysDirectory() + THEMES_DIR);

CFileSearch cfs(CFileSearch::XStringVector(1, "*"), theme_dirs);
auto const& sv = cfs.GetFileNames();
Expand Down
16 changes: 9 additions & 7 deletions Source/Core/DolphinWX/Src/Debugger/CodeWindowFunctions.cpp
Expand Up @@ -211,7 +211,9 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event)

if (Core::GetState() == Core::CORE_UNINITIALIZED) return;

std::string mapfile = CBoot::GenerateMapFilename();
std::string existing_map_file, writable_map_file;
bool map_exists = CBoot::FindMapFile(&existing_map_file,
&writable_map_file);
switch (event.GetId())
{
case IDM_CLEARSYMBOLS:
Expand All @@ -238,28 +240,28 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event)
break;
}
case IDM_LOADMAPFILE:
if (!File::Exists(mapfile))
if (!map_exists)
{
g_symbolDB.Clear();
PPCAnalyst::FindFunctions(0x81300000, 0x81800000, &g_symbolDB);
SignatureDB db;
if (db.Load((File::GetSysDirectory() + TOTALDB).c_str()))
db.Apply(&g_symbolDB);
Parent->StatusBarMessage("'%s' not found, scanning for common functions instead", mapfile.c_str());
Parent->StatusBarMessage("'%s' not found, scanning for common functions instead", writable_map_file.c_str());
}
else
{
g_symbolDB.LoadMap(mapfile.c_str());
Parent->StatusBarMessage("Loaded symbols from '%s'", mapfile.c_str());
g_symbolDB.LoadMap(existing_map_file.c_str());
Parent->StatusBarMessage("Loaded symbols from '%s'", existing_map_file.c_str());
}
HLE::PatchFunctions();
NotifyMapLoaded();
break;
case IDM_SAVEMAPFILE:
g_symbolDB.SaveMap(mapfile.c_str());
g_symbolDB.SaveMap(writable_map_file.c_str());
break;
case IDM_SAVEMAPFILEWITHCODES:
g_symbolDB.SaveMap(mapfile.c_str(), true);
g_symbolDB.SaveMap(writable_map_file.c_str(), true);
break;

case IDM_RENAME_SYMBOLS:
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/DolphinWX/Src/ISOFile.cpp
Expand Up @@ -115,7 +115,8 @@ GameListItem::GameListItem(const std::string& _rFileName)
if (IsValid())
{
IniFile ini;
ini.Load(File::GetUserPath(D_GAMECONFIG_IDX) + m_UniqueID + ".ini");
ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + m_UniqueID + ".ini");
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + m_UniqueID + ".ini", true);
ini.Get("EmuState", "EmulationStateId", &m_emu_state);
ini.Get("EmuState", "EmulationIssues", &m_issues);
}
Expand Down
514 changes: 250 additions & 264 deletions Source/Core/DolphinWX/Src/ISOProperties.cpp

Large diffs are not rendered by default.

17 changes: 15 additions & 2 deletions Source/Core/DolphinWX/Src/ISOProperties.h
Expand Up @@ -129,6 +129,7 @@ class CISOProperties : public wxDialog
ID_ENABLEPROGRESSIVESCAN,
ID_ENABLEWIDESCREEN,
ID_EDITCONFIG,
ID_SHOWDEFAULTCONFIG,
ID_EMUSTATE,
ID_EMU_ISSUES,
ID_PATCHES_LIST,
Expand Down Expand Up @@ -163,10 +164,13 @@ class CISOProperties : public wxDialog
IDM_BNRSAVEAS
};

void LaunchExternalEditor(const std::string& filename);

void CreateGUIControls(bool);
void OnClose(wxCloseEvent& event);
void OnCloseClick(wxCommandEvent& event);
void OnEditConfig(wxCommandEvent& event);
void OnShowDefaultConfig(wxCommandEvent& event);
void ListSelectionChanged(wxCommandEvent& event);
void PatchButtonClicked(wxCommandEvent& event);
void ActionReplayButtonClicked(wxCommandEvent& event);
Expand All @@ -193,13 +197,22 @@ class CISOProperties : public wxDialog
void ExportDir(const char* _rFullPath, const char* _rExportFilename,
const int partitionNum = 0);

IniFile GameIni;
std::string GameIniFile;
IniFile GameIniDefault;
IniFile GameIniLocal;
std::string GameIniFileDefault;
std::string GameIniFileLocal;

std::set<std::string> DefaultPatches;
std::set<std::string> DefaultCheats;

void LoadGameConfig();
void PatchList_Load();
void PatchList_Save();
void ActionReplayList_Save();
void ChangeBannerDetails(int lang);

long GetElementStyle(const char* section, const char* key);
void SetCheckboxValueFromGameini(const char* section, const char* key, wxCheckBox* checkbox);
void SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key, wxCheckBox* checkbox);
};
#endif
41 changes: 16 additions & 25 deletions Source/Core/DolphinWX/Src/Main.cpp
Expand Up @@ -249,37 +249,28 @@ bool DolphinApp::OnInit()
}
#endif

#ifdef _WIN32
if (!wxSetWorkingDirectory(StrToWxStr(File::GetExeDirectory())))
{
INFO_LOG(CONSOLE, "Set working directory failed");
}
#else
//create all necessary directories in user directory
//TODO : detect the revision and upgrade where necessary
File::CopyDir(std::string(SHARED_USER_DIR GAMECONFIG_DIR DIR_SEP),
File::GetUserPath(D_GAMECONFIG_IDX));
File::CopyDir(std::string(SHARED_USER_DIR MAPS_DIR DIR_SEP),
File::GetUserPath(D_MAPS_IDX));
File::CopyDir(std::string(SHARED_USER_DIR SHADERS_DIR DIR_SEP),
File::GetUserPath(D_SHADERS_IDX));
File::CopyDir(std::string(SHARED_USER_DIR WII_USER_DIR DIR_SEP),
File::GetUserPath(D_WIIUSER_IDX));
File::CopyDir(std::string(SHARED_USER_DIR OPENCL_DIR DIR_SEP),
File::GetUserPath(D_OPENCL_IDX));
#endif
File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX));
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX));
// Copy initial Wii NAND data from Sys to User.
File::CopyDir(File::GetSysDirectory() + WII_USER_DIR,
File::GetUserPath(D_WIIUSER_IDX));

File::CreateFullPath(File::GetUserPath(D_USER_IDX));
File::CreateFullPath(File::GetUserPath(D_CACHE_IDX));
File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX));
File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX));
File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX));
File::CreateFullPath(File::GetUserPath(D_HIRESTEXTURES_IDX));
File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX));
File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX));
File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX));
File::CreateFullPath(File::GetUserPath(D_GAMESETTINGS_IDX));
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX));
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + USA_DIR DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + EUR_DIR DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + JAP_DIR DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_HIRESTEXTURES_IDX));
File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX));
File::CreateFullPath(File::GetUserPath(D_MAPS_IDX));
File::CreateFullPath(File::GetUserPath(D_OPENCL_IDX));
File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX));
File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX));
File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX));
File::CreateFullPath(File::GetUserPath(D_THEMES_IDX));

LogManager::Init();
SConfig::Init();
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/DolphinWX/Src/PHackSettings.cpp
Expand Up @@ -2,6 +2,7 @@
// Licensed under GPLv2
// Refer to the license.txt file included.

#include "CommonPaths.h"
#include "PHackSettings.h"
#include "ConfigManager.h"
#include "WxUtils.h"
Expand All @@ -18,10 +19,9 @@ CPHackSettings::CPHackSettings(wxWindow* parent, wxWindowID id, const wxString&
{
CreateGUIControls();
std::string _iniFilename;
_iniFilename = File::GetUserPath(D_GAMECONFIG_IDX) + "PH_PRESETS.ini";
_iniFilename = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP "PH_PRESETS.ini";
PHPresetsIni.Load(_iniFilename.c_str());
//PHPresetsIni.SortSections();
//PHPresetsIni.Save(_iniFilename.c_str());
PHPresetsIni.SortSections();

LoadPHackData();
}
Expand Down
9 changes: 7 additions & 2 deletions Source/Core/InputCommon/Src/InputConfig.cpp
Expand Up @@ -3,6 +3,7 @@
// Refer to the license.txt file included.

#include "InputConfig.h"
#include "CommonPaths.h"
#include "../../Core/Src/ConfigManager.h"
#include "../../Core/Src/HW/Wiimote.h"

Expand Down Expand Up @@ -37,7 +38,8 @@ bool InputPlugin::LoadConfig(bool isGC)
type = "Wiimote";
path = "Profiles/Wiimote/";
}
game_ini.Load(File::GetUserPath(D_GAMECONFIG_IDX) + SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID() + ".ini");
game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID() + ".ini");
game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID() + ".ini", true);
for (int i = 0; i < 4; i++)
{
if (game_ini.Exists("Controls", (type + "Profile" + num[i]).c_str()))
Expand All @@ -46,7 +48,10 @@ bool InputPlugin::LoadConfig(bool isGC)
if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + path + profile[i] + ".ini"))
useProfile[i] = true;
else
{
// TODO: Having a PanicAlert for this is dumb.
PanicAlertT("Selected controller profile does not exist");
}
}
}
}
Expand Down Expand Up @@ -94,6 +99,6 @@ void InputPlugin::SaveConfig()
e = controllers.end();
for ( ; i!=e; ++i )
(*i)->SaveConfig(inifile.GetOrCreateSection((*i)->GetName().c_str()));

inifile.Save(ini_filename);
}
3 changes: 2 additions & 1 deletion Source/Core/VideoCommon/Src/OpenCL/OCLTextureDecoder.cpp
Expand Up @@ -5,6 +5,7 @@
#include "OCLTextureDecoder.h"

#include "../OpenCL.h"
#include "CommonPaths.h"
#include "FileUtil.h"

#include <fcntl.h>
Expand Down Expand Up @@ -138,7 +139,7 @@ void TexDecoder_OpenCL_Initialize()
if (err)
{
std::string code;
filename = File::GetUserPath(D_OPENCL_IDX) + "TextureDecoder.cl";
filename = File::GetSysDirectory() + OPENCL_DIR DIR_SEP "TextureDecoder.cl";
if (!File::ReadFileToString(true, filename.c_str(), code))
{
ERROR_LOG(VIDEO, "Failed to load OpenCL code %s - file is missing?", filename.c_str());
Expand Down
170 changes: 67 additions & 103 deletions Source/Core/VideoCommon/Src/VideoConfig.cpp
Expand Up @@ -120,30 +120,45 @@ void VideoConfig::Load(const char *ini_file)
OSD::AddMessage("Warning: Shader Debugging is enabled, performance will suffer heavily", 15000);
}

void VideoConfig::GameIniLoad(const char *ini_file)
void VideoConfig::GameIniLoad(const char* default_ini_file, const char* local_ini_file)
{
IniFile iniFile;
iniFile.Load(ini_file);
bool gfx_override_exists = false;

// XXX: Again, bad place to put OSD messages at (see delroth's comment above)
// XXX: This will add an OSD message for each projection hack value... meh
#define CHECK_SETTING(section, key, var) do { \
decltype(var) temp = var; \
if (iniFile.GetIfExists(section, key, &var) && var != temp) { \
char buf[256]; \
snprintf(buf, sizeof(buf), "Note: Option \"%s\" is overridden by game ini.", key); \
OSD::AddMessage(buf, 7500); \
gfx_override_exists = true; \
} \
} while (0)

iniFile.GetIfExists("Video_Hardware", "VSync", &bVSync);

iniFile.GetIfExists("Video_Settings", "wideScreenHack", &bWidescreenHack);
iniFile.GetIfExists("Video_Settings", "AspectRatio", &iAspectRatio);
iniFile.GetIfExists("Video_Settings", "Crop", &bCrop);
iniFile.GetIfExists("Video_Settings", "UseXFB", &bUseXFB);
iniFile.GetIfExists("Video_Settings", "UseRealXFB", &bUseRealXFB);
iniFile.GetIfExists("Video_Settings", "SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples);
iniFile.GetIfExists("Video_Settings", "DLOptimize", &iCompileDLsLevel);
iniFile.GetIfExists("Video_Settings", "HiresTextures", &bHiresTextures);
iniFile.GetIfExists("Video_Settings", "AnaglyphStereo", &bAnaglyphStereo);
iniFile.GetIfExists("Video_Settings", "AnaglyphStereoSeparation", &iAnaglyphStereoSeparation);
iniFile.GetIfExists("Video_Settings", "AnaglyphFocalAngle", &iAnaglyphFocalAngle);
iniFile.GetIfExists("Video_Settings", "EnablePixelLighting", &bEnablePixelLighting);
iniFile.GetIfExists("Video_Settings", "HackedBufferUpload", &bHackedBufferUpload);
iniFile.GetIfExists("Video_Settings", "FastDepthCalc", &bFastDepthCalc);
iniFile.GetIfExists("Video_Settings", "MSAA", &iMultisampleMode);
IniFile iniFile;
iniFile.Load(default_ini_file);
iniFile.Load(local_ini_file, true);

CHECK_SETTING("Video_Hardware", "VSync", bVSync);

CHECK_SETTING("Video_Settings", "wideScreenHack", bWidescreenHack);
CHECK_SETTING("Video_Settings", "AspectRatio", iAspectRatio);
CHECK_SETTING("Video_Settings", "Crop", bCrop);
CHECK_SETTING("Video_Settings", "UseXFB", bUseXFB);
CHECK_SETTING("Video_Settings", "UseRealXFB", bUseRealXFB);
CHECK_SETTING("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
CHECK_SETTING("Video_Settings", "DLOptimize", iCompileDLsLevel);
CHECK_SETTING("Video_Settings", "HiresTextures", bHiresTextures);
CHECK_SETTING("Video_Settings", "AnaglyphStereo", bAnaglyphStereo);
CHECK_SETTING("Video_Settings", "AnaglyphStereoSeparation", iAnaglyphStereoSeparation);
CHECK_SETTING("Video_Settings", "AnaglyphFocalAngle", iAnaglyphFocalAngle);
CHECK_SETTING("Video_Settings", "EnablePixelLighting", bEnablePixelLighting);
CHECK_SETTING("Video_Settings", "HackedBufferUpload", bHackedBufferUpload);
CHECK_SETTING("Video_Settings", "FastDepthCalc", bFastDepthCalc);
CHECK_SETTING("Video_Settings", "MSAA", iMultisampleMode);
int tmp = -9000;
iniFile.GetIfExists("Video_Settings", "EFBScale", &tmp); // integral
CHECK_SETTING("Video_Settings", "EFBScale", tmp); // integral
if (tmp != -9000)
{
if (tmp != SCALE_FORCE_INTEGRAL)
Expand All @@ -169,33 +184,36 @@ void VideoConfig::GameIniLoad(const char *ini_file)
}
}

iniFile.GetIfExists("Video_Settings", "DstAlphaPass", &bDstAlphaPass);
iniFile.GetIfExists("Video_Settings", "DisableFog", &bDisableFog);
iniFile.GetIfExists("Video_Settings", "EnableOpenCL", &bEnableOpenCL);
iniFile.GetIfExists("Video_Settings", "OMPDecoder", &bOMPDecoder);

iniFile.GetIfExists("Video_Enhancements", "ForceFiltering", &bForceFiltering);
iniFile.GetIfExists("Video_Enhancements", "MaxAnisotropy", &iMaxAnisotropy); // NOTE - this is x in (1 << x)
iniFile.GetIfExists("Video_Enhancements", "PostProcessingShader", &sPostProcessingShader);
iniFile.GetIfExists("Video_Enhancements", "Enable3dVision", &b3DVision);

iniFile.GetIfExists("Video_Hacks", "EFBAccessEnable", &bEFBAccessEnable);
iniFile.GetIfExists("Video_Hacks", "DlistCachingEnable", &bDlistCachingEnable);
iniFile.GetIfExists("Video_Hacks", "EFBCopyEnable", &bEFBCopyEnable);
iniFile.GetIfExists("Video_Hacks", "EFBToTextureEnable", &bCopyEFBToTexture);
iniFile.GetIfExists("Video_Hacks", "EFBScaledCopy", &bCopyEFBScaled);
iniFile.GetIfExists("Video_Hacks", "EFBCopyCacheEnable", &bEFBCopyCacheEnable);
iniFile.GetIfExists("Video_Hacks", "EFBEmulateFormatChanges", &bEFBEmulateFormatChanges);

iniFile.GetIfExists("Video", "ProjectionHack", &iPhackvalue[0]);
iniFile.GetIfExists("Video", "PH_SZNear", &iPhackvalue[1]);
iniFile.GetIfExists("Video", "PH_SZFar", &iPhackvalue[2]);
iniFile.GetIfExists("Video", "PH_ExtraParam", &iPhackvalue[3]);
iniFile.GetIfExists("Video", "PH_ZNear", &sPhackvalue[0]);
iniFile.GetIfExists("Video", "PH_ZFar", &sPhackvalue[1]);
iniFile.GetIfExists("Video", "ZTPSpeedupHack", &bZTPSpeedHack);
iniFile.GetIfExists("Video", "UseBBox", &bUseBBox);
iniFile.GetIfExists("Video", "PerfQueriesEnable", &bPerfQueriesEnable);
CHECK_SETTING("Video_Settings", "DstAlphaPass", bDstAlphaPass);
CHECK_SETTING("Video_Settings", "DisableFog", bDisableFog);
CHECK_SETTING("Video_Settings", "EnableOpenCL", bEnableOpenCL);
CHECK_SETTING("Video_Settings", "OMPDecoder", bOMPDecoder);

CHECK_SETTING("Video_Enhancements", "ForceFiltering", bForceFiltering);
CHECK_SETTING("Video_Enhancements", "MaxAnisotropy", iMaxAnisotropy); // NOTE - this is x in (1 << x)
CHECK_SETTING("Video_Enhancements", "PostProcessingShader", sPostProcessingShader);
CHECK_SETTING("Video_Enhancements", "Enable3dVision", b3DVision);

CHECK_SETTING("Video_Hacks", "EFBAccessEnable", bEFBAccessEnable);
CHECK_SETTING("Video_Hacks", "DlistCachingEnable", bDlistCachingEnable);
CHECK_SETTING("Video_Hacks", "EFBCopyEnable", bEFBCopyEnable);
CHECK_SETTING("Video_Hacks", "EFBToTextureEnable", bCopyEFBToTexture);
CHECK_SETTING("Video_Hacks", "EFBScaledCopy", bCopyEFBScaled);
CHECK_SETTING("Video_Hacks", "EFBCopyCacheEnable", bEFBCopyCacheEnable);
CHECK_SETTING("Video_Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges);

CHECK_SETTING("Video", "ProjectionHack", iPhackvalue[0]);
CHECK_SETTING("Video", "PH_SZNear", iPhackvalue[1]);
CHECK_SETTING("Video", "PH_SZFar", iPhackvalue[2]);
CHECK_SETTING("Video", "PH_ExtraParam", iPhackvalue[3]);
CHECK_SETTING("Video", "PH_ZNear", sPhackvalue[0]);
CHECK_SETTING("Video", "PH_ZFar", sPhackvalue[1]);
CHECK_SETTING("Video", "ZTPSpeedupHack", bZTPSpeedHack);
CHECK_SETTING("Video", "UseBBox", bUseBBox);
CHECK_SETTING("Video", "PerfQueriesEnable", bPerfQueriesEnable);

if (gfx_override_exists)
OSD::AddMessage("Warning: Opening the graphics configuration will reset settings and might cause issues!", 10000);
}

void VideoConfig::VerifyValidity()
Expand Down Expand Up @@ -262,7 +280,7 @@ void VideoConfig::Save(const char *ini_file)
iniFile.Set("Hacks", "EFBAccessEnable", bEFBAccessEnable);
iniFile.Set("Hacks", "DlistCachingEnable", bDlistCachingEnable);
iniFile.Set("Hacks", "EFBCopyEnable", bEFBCopyEnable);
iniFile.Set("Hacks", "EFBToTextureEnable", bCopyEFBToTexture);
iniFile.Set("Hacks", "EFBToTextureEnable", bCopyEFBToTexture);
iniFile.Set("Hacks", "EFBScaledCopy", bCopyEFBScaled);
iniFile.Set("Hacks", "EFBCopyCacheEnable", bEFBCopyCacheEnable);
iniFile.Set("Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges);
Expand All @@ -273,60 +291,6 @@ void VideoConfig::Save(const char *ini_file)
iniFile.Save(ini_file);
}

void VideoConfig::GameIniSave(const char* default_ini, const char* game_ini)
{
// wxWidgets doesn't provide us with a nice way to change 3-state checkboxes into 2-state ones
// This would allow us to make the "default config" dialog layout to be 2-state based, but the
// "game config" layout to be 3-state based (with the 3rd state being "use default")
// Since we can't do that, we instead just save anything which differs from the default config
// TODO: Make this less ugly

VideoConfig defCfg;
defCfg.Load(default_ini);

IniFile iniFile;
iniFile.Load(game_ini);

#define SET_IF_DIFFERS(section, key, member) { if ((member) != (defCfg.member)) iniFile.Set((section), (key), (member)); else iniFile.DeleteKey((section), (key)); }

SET_IF_DIFFERS("Video_Hardware", "VSync", bVSync);

SET_IF_DIFFERS("Video_Settings", "wideScreenHack", bWidescreenHack);
SET_IF_DIFFERS("Video_Settings", "AspectRatio", iAspectRatio);
SET_IF_DIFFERS("Video_Settings", "Crop", bCrop);
SET_IF_DIFFERS("Video_Settings", "UseXFB", bUseXFB);
SET_IF_DIFFERS("Video_Settings", "UseRealXFB", bUseRealXFB);
SET_IF_DIFFERS("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
SET_IF_DIFFERS("Video_Settings", "DLOptimize", iCompileDLsLevel);
SET_IF_DIFFERS("Video_Settings", "HiresTextures", bHiresTextures);
SET_IF_DIFFERS("Video_Settings", "AnaglyphStereo", bAnaglyphStereo);
SET_IF_DIFFERS("Video_Settings", "AnaglyphStereoSeparation", iAnaglyphStereoSeparation);
SET_IF_DIFFERS("Video_Settings", "AnaglyphFocalAngle", iAnaglyphFocalAngle);
SET_IF_DIFFERS("Video_Settings", "EnablePixelLighting", bEnablePixelLighting);
SET_IF_DIFFERS("Video_Settings", "FastDepthCalc", bFastDepthCalc);
SET_IF_DIFFERS("Video_Settings", "MSAA", iMultisampleMode);
SET_IF_DIFFERS("Video_Settings", "EFBScale", iEFBScale); // integral
SET_IF_DIFFERS("Video_Settings", "DstAlphaPass", bDstAlphaPass);
SET_IF_DIFFERS("Video_Settings", "DisableFog", bDisableFog);
SET_IF_DIFFERS("Video_Settings", "EnableOpenCL", bEnableOpenCL);
SET_IF_DIFFERS("Video_Settings", "OMPDecoder", bOMPDecoder);

SET_IF_DIFFERS("Video_Enhancements", "ForceFiltering", bForceFiltering);
SET_IF_DIFFERS("Video_Enhancements", "MaxAnisotropy", iMaxAnisotropy); // NOTE - this is x in (1 << x)
SET_IF_DIFFERS("Video_Enhancements", "PostProcessingShader", sPostProcessingShader);
SET_IF_DIFFERS("Video_Enhancements", "Enable3dVision", b3DVision);

SET_IF_DIFFERS("Video_Hacks", "EFBAccessEnable", bEFBAccessEnable);
SET_IF_DIFFERS("Video_Hacks", "DlistCachingEnable", bDlistCachingEnable);
SET_IF_DIFFERS("Video_Hacks", "EFBCopyEnable", bEFBCopyEnable);
SET_IF_DIFFERS("Video_Hacks", "EFBToTextureEnable", bCopyEFBToTexture);
SET_IF_DIFFERS("Video_Hacks", "EFBScaledCopy", bCopyEFBScaled);
SET_IF_DIFFERS("Video_Hacks", "EFBCopyCacheEnable", bEFBCopyCacheEnable);
SET_IF_DIFFERS("Video_Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges);

iniFile.Save(game_ini);
}

bool VideoConfig::IsVSync()
{
return Core::isTabPressed ? false : bVSync;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoCommon/Src/VideoConfig.h
Expand Up @@ -50,7 +50,7 @@ struct VideoConfig
{
VideoConfig();
void Load(const char *ini_file);
void GameIniLoad(const char *ini_file);
void GameIniLoad(const char* default_ini, const char* game_ini);
void VerifyValidity();
void Save(const char *ini_file);
void GameIniSave(const char* default_ini, const char* game_ini);
Expand Down
4 changes: 3 additions & 1 deletion Source/Plugins/Plugin_VideoDX11/Src/main.cpp
Expand Up @@ -154,8 +154,10 @@ bool VideoBackend::Initialize(void *&window_handle)

frameCount = 0;

const SCoreStartupParameter& core_params = SConfig::GetInstance().m_LocalCoreStartupParameter;

g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_dx11.ini").c_str());
g_Config.GameIniLoad(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIni.c_str());
g_Config.GameIniLoad(core_params.m_strGameIniDefault.c_str(), core_params.m_strGameIniLocal.c_str());
g_Config.UpdateProjectionHack();
g_Config.VerifyValidity();
UpdateActiveConfig();
Expand Down
3 changes: 2 additions & 1 deletion Source/Plugins/Plugin_VideoDX9/Src/main.cpp
Expand Up @@ -150,7 +150,8 @@ bool VideoBackend::Initialize(void *&window_handle)
frameCount = 0;

g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_dx9.ini").c_str());
g_Config.GameIniLoad(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIni.c_str());
g_Config.GameIniLoad(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIniDefault.c_str(),
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIniLocal.c_str());
g_Config.UpdateProjectionHack();
g_Config.VerifyValidity();
// as only some driver/hardware configurations support dual source blending only enable it if is
Expand Down
8 changes: 7 additions & 1 deletion Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp
Expand Up @@ -2,6 +2,7 @@
// Licensed under GPLv2
// Refer to the license.txt file included.

#include "CommonPaths.h"
#include "FileUtil.h"
#include "VideoCommon.h"
#include "VideoConfig.h"
Expand Down Expand Up @@ -150,7 +151,12 @@ void ApplyShader()

// loading shader code
std::string code;
std::string path = File::GetUserPath(D_SHADERS_IDX) + g_ActiveConfig.sPostProcessingShader + ".txt";
std::string path = File::GetUserPath(D_SHADERS_IDX) + g_ActiveConfig.sPostProcessingShader + ".glsl";
if (!File::Exists(path))
{
// Fallback to shared user dir
path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + g_ActiveConfig.sPostProcessingShader + ".glsl";
}
if(!File::ReadFileToString(true, path.c_str(), code)) {
ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str());
return;
Expand Down
42 changes: 28 additions & 14 deletions Source/Plugins/Plugin_VideoOGL/Src/main.cpp
Expand Up @@ -38,6 +38,7 @@ Make AA apply instantly during gameplay if possible

#include "Globals.h"
#include "Atomic.h"
#include "CommonPaths.h"
#include "Thread.h"
#include "LogManager.h"

Expand Down Expand Up @@ -102,25 +103,37 @@ std::string VideoBackend::GetDisplayName()

void GetShaders(std::vector<std::string> &shaders)
{
std::set<std::string> already_found;

shaders.clear();
if (File::IsDirectory(File::GetUserPath(D_SHADERS_IDX)))
static const std::string directories[] = {
File::GetUserPath(D_SHADERS_IDX),
File::GetSysDirectory() + SHADERS_DIR DIR_SEP,
};
for (size_t i = 0; i < ArraySize(directories); ++i)
{
if (!File::IsDirectory(directories[i]))
continue;

File::FSTEntry entry;
File::ScanDirectoryTree(File::GetUserPath(D_SHADERS_IDX), entry);
for (u32 i = 0; i < entry.children.size(); i++)
File::ScanDirectoryTree(directories[i], entry);
for (u32 j = 0; j < entry.children.size(); j++)
{
std::string name = entry.children[i].virtualName.c_str();
if (!strcasecmp(name.substr(name.size() - 4).c_str(), ".txt")) {
name = name.substr(0, name.size() - 4);
shaders.push_back(name);
}
std::string name = entry.children[j].virtualName.c_str();
if (name.size() < 5)
continue;
if (strcasecmp(name.substr(name.size() - 5).c_str(), ".glsl"))
continue;

name = name.substr(0, name.size() - 5);
if (already_found.find(name) != already_found.end())
continue;

already_found.insert(name);
shaders.push_back(name);
}
std::sort(shaders.begin(), shaders.end());
}
else
{
File::CreateDir(File::GetUserPath(D_SHADERS_IDX).c_str());
}
std::sort(shaders.begin(), shaders.end());
}

void InitBackendInfo()
Expand Down Expand Up @@ -159,7 +172,8 @@ bool VideoBackend::Initialize(void *&window_handle)
frameCount = 0;

g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_opengl.ini").c_str());
g_Config.GameIniLoad(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIni.c_str());
g_Config.GameIniLoad(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIniDefault.c_str(),
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIniLocal.c_str());
g_Config.UpdateProjectionHack();
g_Config.VerifyValidity();
UpdateActiveConfig();
Expand Down