pcsx2/common/IniInterface.cpp

416 lines
10 KiB
C++
Raw Normal View History

/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <wx/gdicmn.h>
2021-09-01 20:31:46 +00:00
#include "common/IniInterface.h"
#include "common/Console.h"
const wxRect wxDefaultRect(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, wxDefaultCoord);
wxDirName g_fullBaseDirName = wxDirName(L"");
void SetFullBaseDir(wxDirName appRoot)
{
g_fullBaseDirName = appRoot;
}
static int _calcEnumLength(const wxChar *const *enumArray)
{
int cnt = 0;
while (*enumArray != NULL) {
enumArray++;
cnt++;
}
return cnt;
}
ScopedIniGroup::ScopedIniGroup(IniInterface &mommy, const wxString &group)
: m_mom(mommy)
{
pxAssertDev(wxStringTokenize(group, L"/").Count() <= 1, L"Cannot nest more than one group deep per instance of ScopedIniGroup.");
m_mom.SetPath(group);
}
ScopedIniGroup::~ScopedIniGroup()
{
m_mom.SetPath(L"..");
}
// --------------------------------------------------------------------------------------
// IniInterface (implementations)
// --------------------------------------------------------------------------------------
IniInterface::IniInterface(wxConfigBase &config)
{
m_Config = &config;
}
IniInterface::IniInterface(wxConfigBase *config)
{
m_Config = config;
}
IniInterface::IniInterface()
{
m_Config = wxConfigBase::Get(false);
}
IniInterface::~IniInterface()
{
Flush();
}
void IniInterface::SetPath(const wxString &path)
{
if (m_Config)
m_Config->SetPath(path);
}
void IniInterface::Flush()
{
if (m_Config)
m_Config->Flush();
}
// --------------------------------------------------------------------------------------
// IniLoader (implementations)
// --------------------------------------------------------------------------------------
IniLoader::IniLoader(wxConfigBase &config)
: IniInterface(config)
{
}
IniLoader::IniLoader(wxConfigBase *config)
: IniInterface(config)
{
}
IniLoader::IniLoader()
: IniInterface()
{
}
void IniLoader::Entry(const wxString &var, wxString &value, const wxString defvalue)
{
if (m_Config)
m_Config->Read(var, &value, defvalue);
else
value = defvalue;
}
void IniLoader::Entry(const wxString &var, wxDirName &value, const wxDirName defvalue, bool isAllowRelative)
{
wxString dest;
if (m_Config)
m_Config->Read(var, &dest, wxEmptyString);
if (dest.IsEmpty())
value = defvalue;
else {
value = dest;
if (isAllowRelative)
value = g_fullBaseDirName + value;
Portable mode: now allows fully custom folders, but still allows relocation of pcsx2 folder without breaking (install mode unmodified). Details: The major differences between install and portable modes should now be: 1. Portable mode doesn't use the registry at all. 2. Portable mode uses the folders inside pcsx2 folder as default (install mode has some default at "my documents"). 3. Portable mode tries to save relative paths at the ini file where possible*. Specifically, portable mode now allows to select custom folders for plugins, bios, etc via the standard UI, which allows using several portable pcsx2 folder sharing the same resources (bios, iso, memcards, etc). * Relative paths where possible = the following sequence (thanks to pseudonym for the brilliant idea): 1. If the file/folder is inside pcsx2 folder, it's saved as completely relative (to pcsx2.exe) 2. Else, if the file/folder is at the same drive as pcsx2.exe, it's saved as absolute path without the drive letter (e.g. /ISO/...) 3. Else, saved as absolute path, including the drive letter (for linux, without drive letter naturally). This allows to create a removable drive with (one or more) pcsx2 folder on it, configure all the files/folders to point to the same drive (ISOs, save states, etc), and then take this drive, plug it into another computer (where it will be assigned with a different drive letter), and everything will continue working. Please test it if you can. Bugs here can be inconvenient... git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4507 96395faa-99c1-11dd-bbfe-3dabce05a288
2011-03-29 17:41:11 +00:00
if (value.IsAbsolute())
value.Normalize();
}
}
void IniLoader::Entry(const wxString &var, wxFileName &value, const wxFileName defvalue, bool isAllowRelative)
{
wxString dest(defvalue.GetFullPath());
if (m_Config)
m_Config->Read(var, &dest, defvalue.GetFullPath());
value = dest;
if (isAllowRelative)
value = g_fullBaseDirName + value;
if (value.IsAbsolute())
value.Normalize();
if (value.HasVolume())
value.SetVolume(value.GetVolume().Upper());
}
void IniLoader::Entry(const wxString &var, int &value, const int defvalue)
{
if (m_Config)
m_Config->Read(var, &value, defvalue);
else
value = defvalue;
}
void IniLoader::Entry(const wxString &var, uint &value, const uint defvalue)
{
if (m_Config)
m_Config->Read(var, (int *)&value, (int)defvalue);
else
value = defvalue;
}
void IniLoader::Entry(const wxString &var, bool &value, const bool defvalue)
{
// TODO : Stricter value checking on enabled/disabled?
2020-08-23 03:59:15 +00:00
wxString dest;
if(defvalue)
dest = wxString("enabled");
else
dest = wxString("disabled");
if (m_Config)
m_Config->Read(var, &dest, dest);
value = (dest == L"enabled") || (dest == L"1");
}
bool IniLoader::EntryBitBool(const wxString &var, bool value, const bool defvalue)
{
// Note: 'value' param is used by inisaver only.
bool result;
Entry(var, result, defvalue);
return result;
}
int IniLoader::EntryBitfield(const wxString &var, int value, const int defvalue)
{
int result;
Entry(var, result, defvalue);
return result;
}
2021-08-30 07:10:48 +00:00
void IniLoader::Entry(const wxString &var, double& value, const double defvalue)
{
2021-08-30 07:10:48 +00:00
auto readval = wxString::FromDouble(value);
if (m_Config)
m_Config->Read(var, &readval);
2021-08-30 07:10:48 +00:00
if (!readval.ToDouble(&value))
value = 0.0;
}
void IniLoader::Entry(const wxString &var, wxPoint &value, const wxPoint defvalue)
{
if (!m_Config) {
value = defvalue;
return;
}
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
}
void IniLoader::Entry(const wxString &var, wxSize &value, const wxSize defvalue)
{
if (!m_Config) {
value = defvalue;
return;
}
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
}
void IniLoader::Entry(const wxString &var, wxRect &value, const wxRect defvalue)
{
if (!m_Config) {
value = defvalue;
return;
}
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
}
void IniLoader::_EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue)
{
// Confirm default value sanity...
const int cnt = _calcEnumLength(enumArray);
if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt)) {
Console.Error("(LoadSettings) Default enumeration index is out of bounds. Truncating.");
defvalue = cnt - 1;
}
// Sanity confirmed, proceed with craziness!
if (!m_Config) {
value = defvalue;
return;
}
wxString retval;
m_Config->Read(var, &retval, enumArray[defvalue]);
int i = 0;
while (enumArray[i] != NULL && (retval != enumArray[i]))
i++;
if (enumArray[i] == NULL) {
Console.Warning(L"(LoadSettings) Warning: Unrecognized value '%s' on key '%s'\n\tUsing the default setting of '%s'.",
WX_STR(retval), WX_STR(var), enumArray[defvalue]);
value = defvalue;
} else
value = i;
}
// --------------------------------------------------------------------------------------
// IniSaver (implementations)
// --------------------------------------------------------------------------------------
IniSaver::IniSaver(wxConfigBase &config)
: IniInterface(config)
{
}
IniSaver::IniSaver(wxConfigBase *config)
: IniInterface(config)
{
}
IniSaver::IniSaver()
: IniInterface()
{
}
void IniSaver::Entry(const wxString &var, wxString &value, const wxString defvalue)
{
if (!m_Config)
return;
m_Config->Write(var, value);
}
void IniSaver::Entry(const wxString &var, wxDirName &value, const wxDirName defvalue, bool isAllowRelative)
{
if (!m_Config)
return;
wxDirName res(value);
Portable mode: now allows fully custom folders, but still allows relocation of pcsx2 folder without breaking (install mode unmodified). Details: The major differences between install and portable modes should now be: 1. Portable mode doesn't use the registry at all. 2. Portable mode uses the folders inside pcsx2 folder as default (install mode has some default at "my documents"). 3. Portable mode tries to save relative paths at the ini file where possible*. Specifically, portable mode now allows to select custom folders for plugins, bios, etc via the standard UI, which allows using several portable pcsx2 folder sharing the same resources (bios, iso, memcards, etc). * Relative paths where possible = the following sequence (thanks to pseudonym for the brilliant idea): 1. If the file/folder is inside pcsx2 folder, it's saved as completely relative (to pcsx2.exe) 2. Else, if the file/folder is at the same drive as pcsx2.exe, it's saved as absolute path without the drive letter (e.g. /ISO/...) 3. Else, saved as absolute path, including the drive letter (for linux, without drive letter naturally). This allows to create a removable drive with (one or more) pcsx2 folder on it, configure all the files/folders to point to the same drive (ISOs, save states, etc), and then take this drive, plug it into another computer (where it will be assigned with a different drive letter), and everything will continue working. Please test it if you can. Bugs here can be inconvenient... git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4507 96395faa-99c1-11dd-bbfe-3dabce05a288
2011-03-29 17:41:11 +00:00
if (res.IsAbsolute())
res.Normalize();
Portable mode: now allows fully custom folders, but still allows relocation of pcsx2 folder without breaking (install mode unmodified). Details: The major differences between install and portable modes should now be: 1. Portable mode doesn't use the registry at all. 2. Portable mode uses the folders inside pcsx2 folder as default (install mode has some default at "my documents"). 3. Portable mode tries to save relative paths at the ini file where possible*. Specifically, portable mode now allows to select custom folders for plugins, bios, etc via the standard UI, which allows using several portable pcsx2 folder sharing the same resources (bios, iso, memcards, etc). * Relative paths where possible = the following sequence (thanks to pseudonym for the brilliant idea): 1. If the file/folder is inside pcsx2 folder, it's saved as completely relative (to pcsx2.exe) 2. Else, if the file/folder is at the same drive as pcsx2.exe, it's saved as absolute path without the drive letter (e.g. /ISO/...) 3. Else, saved as absolute path, including the drive letter (for linux, without drive letter naturally). This allows to create a removable drive with (one or more) pcsx2 folder on it, configure all the files/folders to point to the same drive (ISOs, save states, etc), and then take this drive, plug it into another computer (where it will be assigned with a different drive letter), and everything will continue working. Please test it if you can. Bugs here can be inconvenient... git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4507 96395faa-99c1-11dd-bbfe-3dabce05a288
2011-03-29 17:41:11 +00:00
if (isAllowRelative)
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
/*if( value == defvalue )
m_Config->Write( var, wxString() );
else*/
m_Config->Write(var, res.ToString());
}
void IniSaver::Entry(const wxString &var, wxFileName &value, const wxFileName defvalue, bool isAllowRelative)
{
if (!m_Config)
return;
wxFileName res(value);
if (res.IsAbsolute())
res.Normalize();
if (isAllowRelative)
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
m_Config->Write(var, res.GetFullPath());
}
void IniSaver::Entry(const wxString &var, int &value, const int defvalue)
{
if (!m_Config)
return;
m_Config->Write(var, value);
}
void IniSaver::Entry(const wxString &var, uint &value, const uint defvalue)
{
if (!m_Config)
return;
m_Config->Write(var, (int)value);
}
void IniSaver::Entry(const wxString &var, bool &value, const bool defvalue)
{
if (!m_Config)
return;
m_Config->Write(var, value ? L"enabled" : L"disabled");
}
bool IniSaver::EntryBitBool(const wxString &var, bool value, const bool defvalue)
{
if (m_Config)
m_Config->Write(var, value ? L"enabled" : L"disabled");
return value;
}
int IniSaver::EntryBitfield(const wxString &var, int value, const int defvalue)
{
if (m_Config)
m_Config->Write(var, value);
return value;
}
2021-08-30 07:10:48 +00:00
void IniSaver::Entry(const wxString &var, double &value, const double defvalue)
{
if (!m_Config)
return;
2021-08-30 07:10:48 +00:00
m_Config->Write(var, wxString::FromDouble(value));
}
void IniSaver::Entry(const wxString &var, wxPoint &value, const wxPoint defvalue)
{
if (!m_Config)
return;
m_Config->Write(var, ToString(value));
}
void IniSaver::Entry(const wxString &var, wxSize &value, const wxSize defvalue)
{
if (!m_Config)
return;
m_Config->Write(var, ToString(value));
}
void IniSaver::Entry(const wxString &var, wxRect &value, const wxRect defvalue)
{
if (!m_Config)
return;
m_Config->Write(var, ToString(value));
}
void IniSaver::_EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue)
{
const int cnt = _calcEnumLength(enumArray);
// Confirm default value sanity...
if (!IndexBoundsCheck(L"IniSaver EnumDefaultValue", defvalue, cnt)) {
Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating.");
defvalue = cnt - 1;
}
if (!m_Config)
return;
if (value >= cnt) {
Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var));
Console.Indent().Warning(
L"Illegal Value: %d\n"
L"Using Default: %d (%s)\n",
value, defvalue, enumArray[defvalue]);
// Cause a debug assertion, since this is a fully recoverable error.
pxAssert(value < cnt);
value = defvalue;
}
m_Config->Write(var, enumArray[value]);
}