mirror of https://github.com/stella-emu/stella.git
Move properties to sqlite.
This commit is contained in:
parent
05eefdb112
commit
8dba817906
|
@ -99,6 +99,8 @@
|
||||||
"regex": "cpp",
|
"regex": "cpp",
|
||||||
"valarray": "cpp",
|
"valarray": "cpp",
|
||||||
"ranges": "cpp",
|
"ranges": "cpp",
|
||||||
"stop_token": "cpp"
|
"stop_token": "cpp",
|
||||||
|
"version": "cpp",
|
||||||
|
"shared_mutex": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#ifndef COMPOSITE_KEY_VALUE_REPOSITORY_HXX
|
#ifndef COMPOSITE_KEY_VALUE_REPOSITORY_HXX
|
||||||
#define COMPOSITE_KEY_VALUE_REPOSITORY_HXX
|
#define COMPOSITE_KEY_VALUE_REPOSITORY_HXX
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "KeyValueRepository.hxx"
|
#include "KeyValueRepository.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
@ -30,6 +32,8 @@ class CompositeKeyValueRepository
|
||||||
virtual shared_ptr<KeyValueRepository> get(const string& key) = 0;
|
virtual shared_ptr<KeyValueRepository> get(const string& key) = 0;
|
||||||
|
|
||||||
virtual bool has(const string& key) = 0;
|
virtual bool has(const string& key) = 0;
|
||||||
|
|
||||||
|
virtual void remove(const string& key) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COMPOSITE_KEY_VALUE_REPOSITORY_HXX
|
#endif // COMPOSITE_KEY_VALUE_REPOSITORY_HXX
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// SSSS tt lll lll
|
||||||
|
// SS SS tt ll ll
|
||||||
|
// SS tttttt eeee ll ll aaaa
|
||||||
|
// SSSS tt ee ee ll ll aa
|
||||||
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||||
|
// SS SS tt ee ll ll aa aa
|
||||||
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
|
//
|
||||||
|
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
|
||||||
|
// and the Stella Team
|
||||||
|
//
|
||||||
|
// See the file "License.txt" for information on usage and redistribution of
|
||||||
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
#ifndef COMPOSITE_KEY_VALUE_REPOSITORY_NOOP_HXX
|
||||||
|
#define COMPOSITE_KEY_VALUE_REPOSITORY_NOOP_HXX
|
||||||
|
|
||||||
|
#include "repository/CompositeKeyValueRepository.hxx"
|
||||||
|
#include "repository/KeyValueRepositoryNoop.hxx"
|
||||||
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
class CompositeKeyValueRepositoryNoop : public CompositeKeyValueRepository
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
shared_ptr<KeyValueRepository> get(const string& key) { return make_shared<KeyValueRepositoryNoop>(); }
|
||||||
|
|
||||||
|
bool has(const string& key) { return false; }
|
||||||
|
|
||||||
|
void remove(const string& key) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COMPOSITE_KEY_VALUE_REPOSITORY_NOOP_HXX
|
|
@ -34,6 +34,8 @@ class KeyValueRepository
|
||||||
virtual void save(const std::map<string, Variant>& values) = 0;
|
virtual void save(const std::map<string, Variant>& values) = 0;
|
||||||
|
|
||||||
virtual void save(const string& key, const Variant& value) = 0;
|
virtual void save(const string& key, const Variant& value) = 0;
|
||||||
|
|
||||||
|
virtual void remove(const string& key) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEY_VALUE_REPOSITORY_HXX
|
#endif // KEY_VALUE_REPOSITORY_HXX
|
||||||
|
|
|
@ -33,6 +33,8 @@ class KeyValueRepositoryConfigfile : public KeyValueRepository
|
||||||
|
|
||||||
void save(const string& key, const Variant& value) override {}
|
void save(const string& key, const Variant& value) override {}
|
||||||
|
|
||||||
|
void remove(const string& key) override {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
FilesystemNode myFile;
|
FilesystemNode myFile;
|
||||||
|
|
|
@ -31,6 +31,8 @@ class KeyValueRepositoryNoop : public KeyValueRepository
|
||||||
void save(const std::map<string, Variant>& values) override {}
|
void save(const std::map<string, Variant>& values) override {}
|
||||||
|
|
||||||
void save(const string& key, const Variant& value) override {}
|
void save(const string& key, const Variant& value) override {}
|
||||||
|
|
||||||
|
void remove(const string& key) override {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEY_VALUE_REPOSITORY_NOOP_HXX
|
#endif // KEY_VALUE_REPOSITORY_NOOP_HXX
|
||||||
|
|
|
@ -66,11 +66,7 @@ void AbstractKeyValueRepositorySqlite::save(const string& key, const Variant& va
|
||||||
try {
|
try {
|
||||||
SqliteStatement& stmt{stmtInsert(key, value.toString())};
|
SqliteStatement& stmt{stmtInsert(key, value.toString())};
|
||||||
|
|
||||||
stmt
|
stmt.step();
|
||||||
.bind(1, key.c_str())
|
|
||||||
.bind(2, value.toCString())
|
|
||||||
.step();
|
|
||||||
|
|
||||||
stmt.reset();
|
stmt.reset();
|
||||||
}
|
}
|
||||||
catch (const SqliteError& err) {
|
catch (const SqliteError& err) {
|
||||||
|
@ -78,3 +74,16 @@ void AbstractKeyValueRepositorySqlite::save(const string& key, const Variant& va
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void AbstractKeyValueRepositorySqlite::remove(const string& key)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
SqliteStatement& stmt{stmtDelete(key)};
|
||||||
|
|
||||||
|
stmt.step();
|
||||||
|
stmt.reset();
|
||||||
|
}
|
||||||
|
catch (const SqliteError& err) {
|
||||||
|
Logger::info(err.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,10 +16,13 @@ class AbstractKeyValueRepositorySqlite : public KeyValueRepository
|
||||||
|
|
||||||
void save(const string& key, const Variant& value) override;
|
void save(const string& key, const Variant& value) override;
|
||||||
|
|
||||||
|
void remove(const string& key) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual SqliteStatement& stmtInsert(const string& key, const string& value) = 0;
|
virtual SqliteStatement& stmtInsert(const string& key, const string& value) = 0;
|
||||||
virtual SqliteStatement& stmtSelect() = 0;
|
virtual SqliteStatement& stmtSelect() = 0;
|
||||||
|
virtual SqliteStatement& stmtDelete(const string& key) = 0;
|
||||||
virtual SqliteDatabase& database() = 0;
|
virtual SqliteDatabase& database() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,22 @@ bool CompositeKeyValueRepositorySqlite::has(const string& key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void CompositeKeyValueRepositorySqlite::remove(const string& key)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
myStmtDeleteSet->reset();
|
||||||
|
|
||||||
|
(*myStmtDeleteSet)
|
||||||
|
.bind(1, key.c_str())
|
||||||
|
.step();
|
||||||
|
}
|
||||||
|
catch (const SqliteError& err) {
|
||||||
|
Logger::info(err.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CompositeKeyValueRepositorySqlite::initialize()
|
void CompositeKeyValueRepositorySqlite::initialize()
|
||||||
{
|
{
|
||||||
|
@ -63,6 +79,8 @@ void CompositeKeyValueRepositorySqlite::initialize()
|
||||||
myStmtInsert = make_unique<SqliteStatement>(myDb, "INSERT OR REPLACE INTO `" + myTableName + "` VALUES (?, ?, ?)");
|
myStmtInsert = make_unique<SqliteStatement>(myDb, "INSERT OR REPLACE INTO `" + myTableName + "` VALUES (?, ?, ?)");
|
||||||
myStmtSelect = make_unique<SqliteStatement>(myDb, "SELECT `key2`, `VALUE` FROM `" + myTableName + "` WHERE `key1` = ?");
|
myStmtSelect = make_unique<SqliteStatement>(myDb, "SELECT `key2`, `VALUE` FROM `" + myTableName + "` WHERE `key1` = ?");
|
||||||
myStmtCount = make_unique<SqliteStatement>(myDb, "SELECT COUNT(*) FROM `" + myTableName + "` WHERE `key1` = ?");
|
myStmtCount = make_unique<SqliteStatement>(myDb, "SELECT COUNT(*) FROM `" + myTableName + "` WHERE `key1` = ?");
|
||||||
|
myStmtDelete = make_unique<SqliteStatement>(myDb, "DELETE FROM `" + myTableName + "` WHERE `key1` = ? AND `key2` = ?");
|
||||||
|
myStmtDeleteSet = make_unique<SqliteStatement>(myDb, "DELETE FROM `" + myTableName + "` WHERE `key1` = ?");
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -93,6 +111,17 @@ SqliteStatement& CompositeKeyValueRepositorySqlite::ProxyRepository::stmtSelect(
|
||||||
.bind(1, myKey.c_str());
|
.bind(1, myKey.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
SqliteStatement& CompositeKeyValueRepositorySqlite::ProxyRepository::stmtDelete(const string& key)
|
||||||
|
{
|
||||||
|
myRepo.myStmtDelete->reset();
|
||||||
|
|
||||||
|
return (*myRepo.myStmtDelete)
|
||||||
|
.bind(1, myKey.c_str())
|
||||||
|
.bind(2, key.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
SqliteDatabase& CompositeKeyValueRepositorySqlite::ProxyRepository::database()
|
SqliteDatabase& CompositeKeyValueRepositorySqlite::ProxyRepository::database()
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,6 +33,8 @@ class CompositeKeyValueRepositorySqlite : public CompositeKeyValueRepository {
|
||||||
|
|
||||||
bool has(const string& key) override;
|
bool has(const string& key) override;
|
||||||
|
|
||||||
|
void remove(const string& key) override;
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -46,6 +48,7 @@ class CompositeKeyValueRepositorySqlite : public CompositeKeyValueRepository {
|
||||||
|
|
||||||
SqliteStatement& stmtInsert(const string& key, const string& value) override;
|
SqliteStatement& stmtInsert(const string& key, const string& value) override;
|
||||||
SqliteStatement& stmtSelect() override;
|
SqliteStatement& stmtSelect() override;
|
||||||
|
SqliteStatement& stmtDelete(const string& key) override;
|
||||||
SqliteDatabase& database() override;
|
SqliteDatabase& database() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -69,6 +72,8 @@ class CompositeKeyValueRepositorySqlite : public CompositeKeyValueRepository {
|
||||||
unique_ptr<SqliteStatement> myStmtInsert;
|
unique_ptr<SqliteStatement> myStmtInsert;
|
||||||
unique_ptr<SqliteStatement> myStmtSelect;
|
unique_ptr<SqliteStatement> myStmtSelect;
|
||||||
unique_ptr<SqliteStatement> myStmtCount;
|
unique_ptr<SqliteStatement> myStmtCount;
|
||||||
|
unique_ptr<SqliteStatement> myStmtDelete;
|
||||||
|
unique_ptr<SqliteStatement> myStmtDeleteSet;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,15 @@ SqliteStatement& KeyValueRepositorySqlite::stmtSelect()
|
||||||
return *myStmtSelect;
|
return *myStmtSelect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
SqliteStatement& KeyValueRepositorySqlite::stmtDelete(const string& key)
|
||||||
|
{
|
||||||
|
myStmtDelete->reset();
|
||||||
|
|
||||||
|
return (*myStmtDelete)
|
||||||
|
.bind(1, key.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
SqliteDatabase& KeyValueRepositorySqlite::database()
|
SqliteDatabase& KeyValueRepositorySqlite::database()
|
||||||
{
|
{
|
||||||
|
@ -59,4 +68,5 @@ void KeyValueRepositorySqlite::initialize()
|
||||||
|
|
||||||
myStmtInsert = make_unique<SqliteStatement>(myDb, "INSERT OR REPLACE INTO `" + myTableName + "` VALUES (?, ?)");
|
myStmtInsert = make_unique<SqliteStatement>(myDb, "INSERT OR REPLACE INTO `" + myTableName + "` VALUES (?, ?)");
|
||||||
myStmtSelect = make_unique<SqliteStatement>(myDb, "SELECT `key`, `VALUE` FROM `" + myTableName + "`");
|
myStmtSelect = make_unique<SqliteStatement>(myDb, "SELECT `key`, `VALUE` FROM `" + myTableName + "`");
|
||||||
|
myStmtDelete = make_unique<SqliteStatement>(myDb, "DELETE FROM `" + myTableName + "` WHERE `key` = ?");
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ class KeyValueRepositorySqlite : public AbstractKeyValueRepositorySqlite
|
||||||
|
|
||||||
SqliteStatement& stmtInsert(const string& key, const string& value) override;
|
SqliteStatement& stmtInsert(const string& key, const string& value) override;
|
||||||
SqliteStatement& stmtSelect() override;
|
SqliteStatement& stmtSelect() override;
|
||||||
|
SqliteStatement& stmtDelete(const string& key) override;
|
||||||
SqliteDatabase& database() override;
|
SqliteDatabase& database() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -44,6 +45,7 @@ class KeyValueRepositorySqlite : public AbstractKeyValueRepositorySqlite
|
||||||
|
|
||||||
unique_ptr<SqliteStatement> myStmtInsert;
|
unique_ptr<SqliteStatement> myStmtInsert;
|
||||||
unique_ptr<SqliteStatement> myStmtSelect;
|
unique_ptr<SqliteStatement> myStmtSelect;
|
||||||
|
unique_ptr<SqliteStatement> myStmtDelete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ class SettingsDb
|
||||||
string myDatabaseDirectory;
|
string myDatabaseDirectory;
|
||||||
string myDatabaseName;
|
string myDatabaseName;
|
||||||
|
|
||||||
unique_ptr<SqliteDatabase> myDb;
|
shared_ptr<SqliteDatabase> myDb;
|
||||||
unique_ptr<KeyValueRepositorySqlite> mySettingsRepository;
|
unique_ptr<KeyValueRepositorySqlite> mySettingsRepository;
|
||||||
unique_ptr<CompositeKeyValueRepositorySqlite> myPropertyRepository;
|
unique_ptr<CompositeKeyValueRepositorySqlite> myPropertyRepository;
|
||||||
};
|
};
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
#include "EmulationWorker.hxx"
|
#include "EmulationWorker.hxx"
|
||||||
#include "AudioSettings.hxx"
|
#include "AudioSettings.hxx"
|
||||||
#include "repository/KeyValueRepositoryNoop.hxx"
|
#include "repository/KeyValueRepositoryNoop.hxx"
|
||||||
|
#include "repository/CompositeKeyValueRepositoryNoop.hxx"
|
||||||
#include "M6532.hxx"
|
#include "M6532.hxx"
|
||||||
|
|
||||||
#include "OSystem.hxx"
|
#include "OSystem.hxx"
|
||||||
|
@ -192,8 +193,6 @@ bool OSystem::create()
|
||||||
myPNGLib = make_unique<PNGLibrary>(*this);
|
myPNGLib = make_unique<PNGLibrary>(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
myPropSet->load(myPropertiesFile);
|
|
||||||
|
|
||||||
// Detect serial port for AtariVox-USB
|
// Detect serial port for AtariVox-USB
|
||||||
// If a previously set port is defined, use it;
|
// If a previously set port is defined, use it;
|
||||||
// otherwise use the first one found (if any)
|
// otherwise use the first one found (if any)
|
||||||
|
@ -230,6 +229,7 @@ void OSystem::loadConfig(const Settings::Options& options)
|
||||||
myConfigFile = FilesystemNode(mySettingsDb->databaseFileName());
|
myConfigFile = FilesystemNode(mySettingsDb->databaseFileName());
|
||||||
|
|
||||||
mySettings->setRepository(createSettingsRepository());
|
mySettings->setRepository(createSettingsRepository());
|
||||||
|
myPropSet->setRepository(createPropertyRepository());
|
||||||
mySettings->load(options);
|
mySettings->load(options);
|
||||||
|
|
||||||
// userDir is NOT affected by '-baseDir'and '-basedirinapp' params
|
// userDir is NOT affected by '-baseDir'and '-basedirinapp' params
|
||||||
|
@ -260,9 +260,6 @@ void OSystem::saveConfig()
|
||||||
Logger::debug("Saving config options ...");
|
Logger::debug("Saving config options ...");
|
||||||
mySettings->save();
|
mySettings->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(myPropSet && myPropSet->save(myPropertiesFile))
|
|
||||||
Logger::debug("Saving properties set ...");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -890,6 +887,14 @@ shared_ptr<KeyValueRepository> OSystem::createSettingsRepository()
|
||||||
: make_shared<KeyValueRepositoryNoop>();
|
: make_shared<KeyValueRepositoryNoop>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompositeKeyValueRepository> OSystem::createPropertyRepository()
|
||||||
|
{
|
||||||
|
return mySettingsDb
|
||||||
|
? shared_ptr<CompositeKeyValueRepository>(mySettingsDb, &mySettingsDb->propertyRepository())
|
||||||
|
: make_shared<CompositeKeyValueRepositoryNoop>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
string OSystem::ourOverrideBaseDir = "";
|
string OSystem::ourOverrideBaseDir = "";
|
||||||
bool OSystem::ourOverrideBaseDirWithApp = false;
|
bool OSystem::ourOverrideBaseDirWithApp = false;
|
||||||
|
|
|
@ -60,6 +60,7 @@ class AudioSettings;
|
||||||
#include "Logger.hxx"
|
#include "Logger.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
#include "repository/KeyValueRepository.hxx"
|
#include "repository/KeyValueRepository.hxx"
|
||||||
|
#include "repository/CompositeKeyValueRepository.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This class provides an interface for accessing operating system specific
|
This class provides an interface for accessing operating system specific
|
||||||
|
@ -450,6 +451,8 @@ class OSystem
|
||||||
|
|
||||||
virtual shared_ptr<KeyValueRepository> createSettingsRepository();
|
virtual shared_ptr<KeyValueRepository> createSettingsRepository();
|
||||||
|
|
||||||
|
virtual shared_ptr<CompositeKeyValueRepository> createPropertyRepository();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// The following methods are system-specific and *must* be
|
// The following methods are system-specific and *must* be
|
||||||
// implemented in derived classes.
|
// implemented in derived classes.
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include <sstream>
|
#include <map>
|
||||||
|
|
||||||
#include "bspf.hxx"
|
|
||||||
#include "Props.hxx"
|
#include "Props.hxx"
|
||||||
|
#include "Variant.hxx"
|
||||||
|
#include "bspf.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Properties::Properties()
|
Properties::Properties()
|
||||||
|
@ -32,6 +33,32 @@ Properties::Properties(const Properties& properties)
|
||||||
copy(properties);
|
copy(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Properties::load(KeyValueRepository& repo)
|
||||||
|
{
|
||||||
|
setDefaults();
|
||||||
|
|
||||||
|
const auto props = repo.load();
|
||||||
|
|
||||||
|
for (const auto& [key, value]: props)
|
||||||
|
set(getPropType(key), value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Properties::save(KeyValueRepository& repo) const
|
||||||
|
{
|
||||||
|
std::map<string, Variant> props;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < static_cast<size_t>(PropType::NumTypes); i++) {
|
||||||
|
if (myProperties[i] == ourDefaultProperties[i])
|
||||||
|
repo.remove(ourPropertyNames[i]);
|
||||||
|
else
|
||||||
|
props[ourPropertyNames[i]] = myProperties[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
repo.save(props);
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Properties::set(PropType key, const string& value)
|
void Properties::set(PropType key, const string& value)
|
||||||
{
|
{
|
||||||
|
@ -79,120 +106,6 @@ void Properties::set(PropType key, const string& value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
istream& operator>>(istream& is, Properties& p)
|
|
||||||
{
|
|
||||||
p.setDefaults();
|
|
||||||
|
|
||||||
// Loop reading properties
|
|
||||||
string key, value;
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
// Get the key associated with this property
|
|
||||||
key = p.readQuotedString(is);
|
|
||||||
|
|
||||||
// Make sure the stream is still okay
|
|
||||||
if(!is)
|
|
||||||
return is;
|
|
||||||
|
|
||||||
// A null key signifies the end of the property list
|
|
||||||
if(key == "")
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Get the value associated with this property
|
|
||||||
value = p.readQuotedString(is);
|
|
||||||
|
|
||||||
// Make sure the stream is still okay
|
|
||||||
if(!is)
|
|
||||||
return is;
|
|
||||||
|
|
||||||
// Set the property
|
|
||||||
PropType type = Properties::getPropType(key);
|
|
||||||
p.set(type, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return is;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
ostream& operator<<(ostream& os, const Properties& p)
|
|
||||||
{
|
|
||||||
// Write out each of the key and value pairs
|
|
||||||
bool changed = false;
|
|
||||||
for(size_t i = 0; i < static_cast<size_t>(PropType::NumTypes); ++i)
|
|
||||||
{
|
|
||||||
// Try to save some space by only saving the items that differ from default
|
|
||||||
if(p.myProperties[i] != Properties::ourDefaultProperties[i])
|
|
||||||
{
|
|
||||||
p.writeQuotedString(os, Properties::ourPropertyNames[i]);
|
|
||||||
os.put(' ');
|
|
||||||
p.writeQuotedString(os, p.myProperties[i]);
|
|
||||||
os.put('\n');
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(changed)
|
|
||||||
{
|
|
||||||
// Put a trailing null string so we know when to stop reading
|
|
||||||
p.writeQuotedString(os, "");
|
|
||||||
os.put('\n');
|
|
||||||
os.put('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
string Properties::readQuotedString(istream& in)
|
|
||||||
{
|
|
||||||
// Read characters until we see a quote
|
|
||||||
char c;
|
|
||||||
while(in.get(c))
|
|
||||||
if(c == '"')
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Read characters until we see the close quote
|
|
||||||
string s;
|
|
||||||
while(in.get(c))
|
|
||||||
{
|
|
||||||
if((c == '\\') && (in.peek() == '"'))
|
|
||||||
in.get(c);
|
|
||||||
else if((c == '\\') && (in.peek() == '\\'))
|
|
||||||
in.get(c);
|
|
||||||
else if(c == '"')
|
|
||||||
break;
|
|
||||||
else if(c == '\r')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
s += c;
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void Properties::writeQuotedString(ostream& out, const string& s)
|
|
||||||
{
|
|
||||||
out.put('"');
|
|
||||||
for(uInt32 i = 0; i < s.length(); ++i)
|
|
||||||
{
|
|
||||||
if(s[i] == '\\')
|
|
||||||
{
|
|
||||||
out.put('\\');
|
|
||||||
out.put('\\');
|
|
||||||
}
|
|
||||||
else if(s[i] == '\"')
|
|
||||||
{
|
|
||||||
out.put('\\');
|
|
||||||
out.put('"');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
out.put(s[i]);
|
|
||||||
}
|
|
||||||
out.put('"');
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Properties::operator==(const Properties& properties) const
|
bool Properties::operator==(const Properties& properties) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#ifndef PROPERTIES_HXX
|
#ifndef PROPERTIES_HXX
|
||||||
#define PROPERTIES_HXX
|
#define PROPERTIES_HXX
|
||||||
|
|
||||||
|
#include "repository/KeyValueRepository.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
enum class PropType : uInt8 {
|
enum class PropType : uInt8 {
|
||||||
|
@ -81,6 +82,10 @@ class Properties
|
||||||
Properties(const Properties& properties);
|
Properties(const Properties& properties);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void load(KeyValueRepository& repo);
|
||||||
|
|
||||||
|
void save(KeyValueRepository& repo) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the value assigned to the specified key. If the key does
|
Get the value assigned to the specified key. If the key does
|
||||||
not exist then the empty string is returned.
|
not exist then the empty string is returned.
|
||||||
|
@ -101,22 +106,6 @@ class Properties
|
||||||
*/
|
*/
|
||||||
void set(PropType key, const string& value);
|
void set(PropType key, const string& value);
|
||||||
|
|
||||||
/**
|
|
||||||
Load properties from the specified input stream
|
|
||||||
|
|
||||||
@param is The input stream to use
|
|
||||||
@param p The Properties object to write to
|
|
||||||
*/
|
|
||||||
friend istream& operator>>(istream& is, Properties& p);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Save properties to the specified output stream
|
|
||||||
|
|
||||||
@param os The output stream to use
|
|
||||||
@param p The Properties object to read from
|
|
||||||
*/
|
|
||||||
friend ostream& operator<<(ostream& os, const Properties& p);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Print the attributes of this properties object
|
Print the attributes of this properties object
|
||||||
*/
|
*/
|
||||||
|
@ -169,24 +158,6 @@ class Properties
|
||||||
*/
|
*/
|
||||||
void copy(const Properties& properties);
|
void copy(const Properties& properties);
|
||||||
|
|
||||||
/**
|
|
||||||
Read the next quoted string from the specified input stream
|
|
||||||
and returns it.
|
|
||||||
|
|
||||||
@param in The input stream to use
|
|
||||||
@return The string inside the quotes
|
|
||||||
*/
|
|
||||||
static string readQuotedString(istream& in);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Write the specified string to the given output stream as a
|
|
||||||
quoted string.
|
|
||||||
|
|
||||||
@param out The output stream to use
|
|
||||||
@param s The string to output
|
|
||||||
*/
|
|
||||||
static void writeQuotedString(ostream& out, const string& s);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the property type associated with the named property
|
Get the property type associated with the named property
|
||||||
|
|
||||||
|
|
|
@ -23,51 +23,15 @@
|
||||||
#include "DefProps.hxx"
|
#include "DefProps.hxx"
|
||||||
#include "Props.hxx"
|
#include "Props.hxx"
|
||||||
#include "PropsSet.hxx"
|
#include "PropsSet.hxx"
|
||||||
|
#include "repository/CompositeKeyValueRepositoryNoop.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void PropertiesSet::load(const FilesystemNode& file, bool save)
|
PropertiesSet::PropertiesSet() : myRepository{make_shared<CompositeKeyValueRepositoryNoop>()} {}
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
stringstream in;
|
|
||||||
if(file.exists() && file.read(in) > 0)
|
|
||||||
{
|
|
||||||
Properties prop;
|
|
||||||
while(in >> prop)
|
|
||||||
insert(prop, save);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool PropertiesSet::save(const FilesystemNode& file) const
|
void PropertiesSet::setRepository(shared_ptr<CompositeKeyValueRepository> repository)
|
||||||
{
|
{
|
||||||
try
|
myRepository = repository;
|
||||||
{
|
|
||||||
// Only save properties when it won't create an empty file
|
|
||||||
if(!file.exists() && myExternalProps.size() == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Only save those entries in the external list
|
|
||||||
stringstream out;
|
|
||||||
for(const auto& i: myExternalProps)
|
|
||||||
out << i.second;
|
|
||||||
|
|
||||||
file.write(out);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch(const runtime_error& e)
|
|
||||||
{
|
|
||||||
Logger::error(e.what());
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -88,11 +52,9 @@ bool PropertiesSet::getMD5(const string& md5, Properties& properties,
|
||||||
// First check properties from external file
|
// First check properties from external file
|
||||||
if(!useDefaults)
|
if(!useDefaults)
|
||||||
{
|
{
|
||||||
// Check external list
|
if (myRepository->has(md5)) {
|
||||||
auto ext = myExternalProps.find(md5);
|
properties.load(*myRepository->get(md5));
|
||||||
if(ext != myExternalProps.end())
|
|
||||||
{
|
|
||||||
properties = ext->second;
|
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
else // Search temp list
|
else // Search temp list
|
||||||
|
@ -138,6 +100,7 @@ bool PropertiesSet::getMD5(const string& md5, Properties& properties,
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void PropertiesSet::insert(const Properties& properties, bool save)
|
void PropertiesSet::insert(const Properties& properties, bool save)
|
||||||
{
|
{
|
||||||
|
// TODO
|
||||||
// Note that the following code is optimized for insertion when an item
|
// Note that the following code is optimized for insertion when an item
|
||||||
// doesn't already exist, and when the external properties file is
|
// doesn't already exist, and when the external properties file is
|
||||||
// relatively small (which is the case with current versions of Stella,
|
// relatively small (which is the case with current versions of Stella,
|
||||||
|
@ -158,19 +121,21 @@ void PropertiesSet::insert(const Properties& properties, bool save)
|
||||||
return;
|
return;
|
||||||
else if(getMD5(md5, defaultProps, true) && defaultProps == properties)
|
else if(getMD5(md5, defaultProps, true) && defaultProps == properties)
|
||||||
{
|
{
|
||||||
myExternalProps.erase(md5);
|
cerr << "DELETE" << endl << std::flush;
|
||||||
|
myRepository->remove(md5);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The status of 'save' determines which list to save to
|
if (save) {
|
||||||
PropsList& list = save ? myExternalProps : myTempProps;
|
properties.save(*myRepository->get(md5));
|
||||||
|
} else {
|
||||||
auto ret = list.emplace(md5, properties);
|
auto ret = myTempProps.emplace(md5, properties);
|
||||||
if(ret.second == false)
|
if(ret.second == false)
|
||||||
{
|
{
|
||||||
// Remove old item and insert again
|
// Remove old item and insert again
|
||||||
list.erase(ret.first);
|
myTempProps.erase(ret.first);
|
||||||
list.emplace(md5, properties);
|
myTempProps.emplace(md5, properties);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,8 +149,11 @@ void PropertiesSet::loadPerROM(const FilesystemNode& rom, const string& md5)
|
||||||
// First, does this ROM have a per-ROM properties entry?
|
// First, does this ROM have a per-ROM properties entry?
|
||||||
// If so, load it into the database
|
// If so, load it into the database
|
||||||
FilesystemNode propsNode(rom.getPathWithExt(".pro"));
|
FilesystemNode propsNode(rom.getPathWithExt(".pro"));
|
||||||
if(propsNode.exists())
|
// CSTODO
|
||||||
load(propsNode, false);
|
#if 0
|
||||||
|
if(propsNode.exists())
|
||||||
|
load(propsNode, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Next, make sure we have a valid md5 and name
|
// Next, make sure we have a valid md5 and name
|
||||||
Properties props;
|
Properties props;
|
||||||
|
|
|
@ -25,6 +25,7 @@ class OSystem;
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
#include "Props.hxx"
|
#include "Props.hxx"
|
||||||
|
#include "repository/CompositeKeyValueRepository.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This class maintains an ordered collection of properties, maintained
|
This class maintains an ordered collection of properties, maintained
|
||||||
|
@ -39,32 +40,10 @@ class OSystem;
|
||||||
class PropertiesSet
|
class PropertiesSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
Trivial constructor.
|
|
||||||
*/
|
|
||||||
PropertiesSet() = default;
|
|
||||||
|
|
||||||
/**
|
PropertiesSet();
|
||||||
Load properties from the specified file, and create an internal
|
|
||||||
searchable list.
|
|
||||||
|
|
||||||
@param file The node representing the input file to use
|
void setRepository(shared_ptr<CompositeKeyValueRepository> repository);
|
||||||
@param save Indicates whether the properties should be saved
|
|
||||||
when the program exits
|
|
||||||
*/
|
|
||||||
void load(const FilesystemNode& file, bool save = true);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Save properties to the specified file.
|
|
||||||
|
|
||||||
@param file The node representing the output file to use
|
|
||||||
|
|
||||||
@return True on success, false on failure or save not needed
|
|
||||||
Failure occurs if file couldn't be opened for writing,
|
|
||||||
or if the file doesn't exist and a zero-byte file
|
|
||||||
would be created
|
|
||||||
*/
|
|
||||||
bool save(const FilesystemNode& file) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the property from the set with the given MD5.
|
Get the property from the set with the given MD5.
|
||||||
|
@ -120,6 +99,8 @@ class PropertiesSet
|
||||||
// be discarded when the program ends
|
// be discarded when the program ends
|
||||||
PropsList myTempProps;
|
PropsList myTempProps;
|
||||||
|
|
||||||
|
shared_ptr<CompositeKeyValueRepository> myRepository;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
PropertiesSet(const PropertiesSet&) = delete;
|
PropertiesSet(const PropertiesSet&) = delete;
|
||||||
|
|
|
@ -0,0 +1,397 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// SSSS tt lll lll
|
||||||
|
// SS SS tt ll ll
|
||||||
|
// SS tttttt eeee ll ll aaaa
|
||||||
|
// SSSS tt ee ee ll ll aa
|
||||||
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||||
|
// SS SS tt ee ll ll aa aa
|
||||||
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
|
//
|
||||||
|
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
|
||||||
|
// and the Stella Team
|
||||||
|
//
|
||||||
|
// See the file "License.txt" for information on usage and redistribution of
|
||||||
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "bspf.hxx"
|
||||||
|
#include "Props.hxx"
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Properties::Properties()
|
||||||
|
{
|
||||||
|
setDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Properties::Properties(const Properties& properties)
|
||||||
|
{
|
||||||
|
copy(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Properties::set(PropType key, const string& value)
|
||||||
|
{
|
||||||
|
size_t pos = static_cast<size_t>(key);
|
||||||
|
if(pos < myProperties.size())
|
||||||
|
{
|
||||||
|
myProperties[pos] = value;
|
||||||
|
if(BSPF::equalsIgnoreCase(myProperties[pos], "AUTO-DETECT"))
|
||||||
|
myProperties[pos] = "AUTO";
|
||||||
|
|
||||||
|
switch(key)
|
||||||
|
{
|
||||||
|
case PropType::Cart_Sound:
|
||||||
|
case PropType::Cart_Type:
|
||||||
|
case PropType::Console_LeftDiff:
|
||||||
|
case PropType::Console_RightDiff:
|
||||||
|
case PropType::Console_TVType:
|
||||||
|
case PropType::Console_SwapPorts:
|
||||||
|
case PropType::Controller_Left:
|
||||||
|
case PropType::Controller_Left1:
|
||||||
|
case PropType::Controller_Left2:
|
||||||
|
case PropType::Controller_Right:
|
||||||
|
case PropType::Controller_Right1:
|
||||||
|
case PropType::Controller_Right2:
|
||||||
|
case PropType::Controller_SwapPaddles:
|
||||||
|
case PropType::Controller_MouseAxis:
|
||||||
|
case PropType::Display_Format:
|
||||||
|
case PropType::Display_Phosphor:
|
||||||
|
{
|
||||||
|
BSPF::toUpperCase(myProperties[pos]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PropType::Display_PPBlend:
|
||||||
|
{
|
||||||
|
int blend = BSPF::stringToInt(myProperties[pos]);
|
||||||
|
if(blend < 0 || blend > 100)
|
||||||
|
myProperties[pos] = ourDefaultProperties[pos];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
istream& operator>>(istream& is, Properties& p)
|
||||||
|
{
|
||||||
|
p.setDefaults();
|
||||||
|
|
||||||
|
// Loop reading properties
|
||||||
|
string key, value;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
// Get the key associated with this property
|
||||||
|
key = p.readQuotedString(is);
|
||||||
|
|
||||||
|
// Make sure the stream is still okay
|
||||||
|
if(!is)
|
||||||
|
return is;
|
||||||
|
|
||||||
|
// A null key signifies the end of the property list
|
||||||
|
if(key == "")
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Get the value associated with this property
|
||||||
|
value = p.readQuotedString(is);
|
||||||
|
|
||||||
|
// Make sure the stream is still okay
|
||||||
|
if(!is)
|
||||||
|
return is;
|
||||||
|
|
||||||
|
// Set the property
|
||||||
|
PropType type = Properties::getPropType(key);
|
||||||
|
p.set(type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
ostream& operator<<(ostream& os, const Properties& p)
|
||||||
|
{
|
||||||
|
// Write out each of the key and value pairs
|
||||||
|
bool changed = false;
|
||||||
|
for(size_t i = 0; i < static_cast<size_t>(PropType::NumTypes); ++i)
|
||||||
|
{
|
||||||
|
// Try to save some space by only saving the items that differ from default
|
||||||
|
if(p.myProperties[i] != Properties::ourDefaultProperties[i])
|
||||||
|
{
|
||||||
|
p.writeQuotedString(os, Properties::ourPropertyNames[i]);
|
||||||
|
os.put(' ');
|
||||||
|
p.writeQuotedString(os, p.myProperties[i]);
|
||||||
|
os.put('\n');
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(changed)
|
||||||
|
{
|
||||||
|
// Put a trailing null string so we know when to stop reading
|
||||||
|
p.writeQuotedString(os, "");
|
||||||
|
os.put('\n');
|
||||||
|
os.put('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
string Properties::readQuotedString(istream& in)
|
||||||
|
{
|
||||||
|
// Read characters until we see a quote
|
||||||
|
char c;
|
||||||
|
while(in.get(c))
|
||||||
|
if(c == '"')
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Read characters until we see the close quote
|
||||||
|
string s;
|
||||||
|
while(in.get(c))
|
||||||
|
{
|
||||||
|
if((c == '\\') && (in.peek() == '"'))
|
||||||
|
in.get(c);
|
||||||
|
else if((c == '\\') && (in.peek() == '\\'))
|
||||||
|
in.get(c);
|
||||||
|
else if(c == '"')
|
||||||
|
break;
|
||||||
|
else if(c == '\r')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
s += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Properties::writeQuotedString(ostream& out, const string& s)
|
||||||
|
{
|
||||||
|
out.put('"');
|
||||||
|
for(uInt32 i = 0; i < s.length(); ++i)
|
||||||
|
{
|
||||||
|
if(s[i] == '\\')
|
||||||
|
{
|
||||||
|
out.put('\\');
|
||||||
|
out.put('\\');
|
||||||
|
}
|
||||||
|
else if(s[i] == '\"')
|
||||||
|
{
|
||||||
|
out.put('\\');
|
||||||
|
out.put('"');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out.put(s[i]);
|
||||||
|
}
|
||||||
|
out.put('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Properties::operator==(const Properties& properties) const
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < myProperties.size(); ++i)
|
||||||
|
if(myProperties[i] != properties.myProperties[i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Properties::operator!=(const Properties& properties) const
|
||||||
|
{
|
||||||
|
return !(*this == properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Properties& Properties::operator=(const Properties& properties)
|
||||||
|
{
|
||||||
|
// Do the assignment only if this isn't a self assignment
|
||||||
|
if(this != &properties)
|
||||||
|
{
|
||||||
|
// Now, make myself a copy of the given object
|
||||||
|
copy(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Properties::setDefault(PropType key, const string& value)
|
||||||
|
{
|
||||||
|
ourDefaultProperties[static_cast<size_t>(key)] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Properties::copy(const Properties& properties)
|
||||||
|
{
|
||||||
|
// Now, copy each property from properties
|
||||||
|
for(size_t i = 0; i < myProperties.size(); ++i)
|
||||||
|
myProperties[i] = properties.myProperties[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Properties::print() const
|
||||||
|
{
|
||||||
|
cout << get(PropType::Cart_MD5) << "|"
|
||||||
|
<< get(PropType::Cart_Name) << "|"
|
||||||
|
<< get(PropType::Cart_Manufacturer) << "|"
|
||||||
|
<< get(PropType::Cart_ModelNo) << "|"
|
||||||
|
<< get(PropType::Cart_Note) << "|"
|
||||||
|
<< get(PropType::Cart_Rarity) << "|"
|
||||||
|
<< get(PropType::Cart_Sound) << "|"
|
||||||
|
<< get(PropType::Cart_StartBank) << "|"
|
||||||
|
<< get(PropType::Cart_Type) << "|"
|
||||||
|
<< get(PropType::Console_LeftDiff) << "|"
|
||||||
|
<< get(PropType::Console_RightDiff) << "|"
|
||||||
|
<< get(PropType::Console_TVType) << "|"
|
||||||
|
<< get(PropType::Console_SwapPorts) << "|"
|
||||||
|
<< get(PropType::Controller_Left) << "|"
|
||||||
|
<< get(PropType::Controller_Left1) << "|"
|
||||||
|
<< get(PropType::Controller_Left2) << "|"
|
||||||
|
<< get(PropType::Controller_Right) << "|"
|
||||||
|
<< get(PropType::Controller_Right1) << "|"
|
||||||
|
<< get(PropType::Controller_Right2) << "|"
|
||||||
|
<< get(PropType::Controller_SwapPaddles) << "|"
|
||||||
|
<< get(PropType::Controller_PaddlesXCenter) << "|"
|
||||||
|
<< get(PropType::Controller_PaddlesYCenter) << "|"
|
||||||
|
<< get(PropType::Controller_MouseAxis) << "|"
|
||||||
|
<< get(PropType::Display_Format) << "|"
|
||||||
|
<< get(PropType::Display_VCenter) << "|"
|
||||||
|
<< get(PropType::Display_Phosphor) << "|"
|
||||||
|
<< get(PropType::Display_PPBlend) << "|"
|
||||||
|
<< get(PropType::Cart_Highscore)
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Properties::reset(PropType key)
|
||||||
|
{
|
||||||
|
size_t pos = static_cast<size_t>(key);
|
||||||
|
|
||||||
|
myProperties[pos] = ourDefaultProperties[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Properties::setDefaults()
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < myProperties.size(); ++i)
|
||||||
|
myProperties[i] = ourDefaultProperties[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
PropType Properties::getPropType(const string& name)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < NUM_PROPS; ++i)
|
||||||
|
if(ourPropertyNames[i] == name)
|
||||||
|
return static_cast<PropType>(i);
|
||||||
|
|
||||||
|
// Otherwise, indicate that the item wasn't found
|
||||||
|
return PropType::NumTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Properties::printHeader()
|
||||||
|
{
|
||||||
|
cout << "Cart_MD5|"
|
||||||
|
<< "Cart_Name|"
|
||||||
|
<< "Cart_Manufacturer|"
|
||||||
|
<< "Cart_ModelNo|"
|
||||||
|
<< "Cart_Note|"
|
||||||
|
<< "Cart_Rarity|"
|
||||||
|
<< "Cart_Sound|"
|
||||||
|
<< "Cart_StartBank|"
|
||||||
|
<< "Cart_Type|"
|
||||||
|
<< "Console_LeftDiff|"
|
||||||
|
<< "Console_RightDiff|"
|
||||||
|
<< "Console_TVType|"
|
||||||
|
<< "Console_SwapPorts|"
|
||||||
|
<< "Controller_Left|"
|
||||||
|
<< "Controller_Left1|"
|
||||||
|
<< "Controller_Left2|"
|
||||||
|
<< "Controller_Right|"
|
||||||
|
<< "Controller_Right1|"
|
||||||
|
<< "Controller_Right2|"
|
||||||
|
<< "Controller_SwapPaddles|"
|
||||||
|
<< "Controller_PaddlesXCenter|"
|
||||||
|
<< "Controller_PaddlesYCenter|"
|
||||||
|
<< "Controller_MouseAxis|"
|
||||||
|
<< "Display_Format|"
|
||||||
|
<< "Display_VCenter|"
|
||||||
|
<< "Display_Phosphor|"
|
||||||
|
<< "Display_PPBlend|"
|
||||||
|
<< "Cart_Highscore"
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
std::array<string, Properties::NUM_PROPS> Properties::ourDefaultProperties =
|
||||||
|
{
|
||||||
|
"", // Cart.MD5
|
||||||
|
"", // Cart.Manufacturer
|
||||||
|
"", // Cart.ModelNo
|
||||||
|
"", // Cart.Name
|
||||||
|
"", // Cart.Note
|
||||||
|
"", // Cart.Rarity
|
||||||
|
"MONO", // Cart.Sound
|
||||||
|
"AUTO", // Cart.StartBank
|
||||||
|
"AUTO", // Cart.Type
|
||||||
|
"B", // Console.LeftDiff
|
||||||
|
"B", // Console.RightDiff
|
||||||
|
"COLOR", // Console.TVType
|
||||||
|
"NO", // Console.SwapPorts
|
||||||
|
"AUTO", // Controller.Left
|
||||||
|
"", // Controller.Left1
|
||||||
|
"", // Controller.Left2
|
||||||
|
"AUTO", // Controller.Right
|
||||||
|
"", // Controller.Right1
|
||||||
|
"", // Controller.Right2
|
||||||
|
"NO", // Controller.SwapPaddles
|
||||||
|
"0", // Controller.PaddlesXCenter
|
||||||
|
"0", // Controller.PaddlesYCenter
|
||||||
|
"AUTO", // Controller.MouseAxis
|
||||||
|
"AUTO", // Display.Format
|
||||||
|
"0", // Display.VCenter
|
||||||
|
"NO", // Display.Phosphor
|
||||||
|
"0", // Display.PPBlend
|
||||||
|
"" // Cart.Highscore
|
||||||
|
};
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
std::array<string, Properties::NUM_PROPS> Properties::ourPropertyNames =
|
||||||
|
{
|
||||||
|
"Cart.MD5",
|
||||||
|
"Cart.Manufacturer",
|
||||||
|
"Cart.ModelNo",
|
||||||
|
"Cart.Name",
|
||||||
|
"Cart.Note",
|
||||||
|
"Cart.Rarity",
|
||||||
|
"Cart.Sound",
|
||||||
|
"Cart.StartBank",
|
||||||
|
"Cart.Type",
|
||||||
|
"Console.LeftDiff",
|
||||||
|
"Console.RightDiff",
|
||||||
|
"Console.TVType",
|
||||||
|
"Console.SwapPorts",
|
||||||
|
"Controller.Left",
|
||||||
|
"Controller.Left1",
|
||||||
|
"Controller.Left2",
|
||||||
|
"Controller.Right",
|
||||||
|
"Controller.Right1",
|
||||||
|
"Controller.Right2",
|
||||||
|
"Controller.SwapPaddles",
|
||||||
|
"Controller.PaddlesXCenter",
|
||||||
|
"Controller.PaddlesYCenter",
|
||||||
|
"Controller.MouseAxis",
|
||||||
|
"Display.Format",
|
||||||
|
"Display.VCenter",
|
||||||
|
"Display.Phosphor",
|
||||||
|
"Display.PPBlend",
|
||||||
|
"Cart.Highscore"
|
||||||
|
};
|
|
@ -1333,6 +1333,9 @@ void GameInfoDialog::setAddressVal(EditTextWidget* addressWidget, EditTextWidget
|
||||||
void GameInfoDialog::exportCurrentPropertiesToDisk(const FilesystemNode& node)
|
void GameInfoDialog::exportCurrentPropertiesToDisk(const FilesystemNode& node)
|
||||||
{
|
{
|
||||||
saveProperties();
|
saveProperties();
|
||||||
|
|
||||||
|
// CSTODO
|
||||||
|
#if 0
|
||||||
stringstream out;
|
stringstream out;
|
||||||
out << myGameProperties;
|
out << myGameProperties;
|
||||||
|
|
||||||
|
@ -1345,6 +1348,8 @@ void GameInfoDialog::exportCurrentPropertiesToDisk(const FilesystemNode& node)
|
||||||
{
|
{
|
||||||
instance().frameBuffer().showTextMessage("Error exporting ROM properties");
|
instance().frameBuffer().showTextMessage("Error exporting ROM properties");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
Loading…
Reference in New Issue