Reimplement export / load of per-ROM properties.

This commit is contained in:
Christian Speckner 2020-12-31 00:00:48 +01:00
parent 14739497a1
commit e8330f5600
16 changed files with 254 additions and 42 deletions

View File

@ -32,6 +32,7 @@ MODULE_OBJS := \
src/common/sdl_blitter/BilinearBlitter.o \ src/common/sdl_blitter/BilinearBlitter.o \
src/common/sdl_blitter/QisBlitter.o \ src/common/sdl_blitter/QisBlitter.o \
src/common/sdl_blitter/BlitterFactory.o \ src/common/sdl_blitter/BlitterFactory.o \
src/common/repository/KeyValueRepositoryPropertyFile.o \
MODULE_DIRS += \ MODULE_DIRS += \
src/common src/common

View File

@ -31,9 +31,9 @@ class KeyValueRepository
virtual std::map<string, Variant> load() = 0; virtual std::map<string, Variant> load() = 0;
virtual void save(const std::map<string, Variant>& values) = 0; virtual bool save(const std::map<string, Variant>& values) = 0;
virtual void save(const string& key, const Variant& value) = 0; virtual bool save(const string& key, const Variant& value) = 0;
virtual void remove(const string& key) = 0; virtual void remove(const string& key) = 0;
}; };

View File

@ -72,7 +72,7 @@ std::map<string, Variant> KeyValueRepositoryConfigfile::load()
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KeyValueRepositoryConfigfile::save(const std::map<string, Variant>& values) bool KeyValueRepositoryConfigfile::save(const std::map<string, Variant>& values)
{ {
stringstream out; stringstream out;
out << "; Stella configuration file" << endl out << "; Stella configuration file" << endl
@ -97,9 +97,13 @@ void KeyValueRepositoryConfigfile::save(const std::map<string, Variant>& values)
try try
{ {
myFile.write(out); myFile.write(out);
return true;
} }
catch(...) catch(...)
{ {
Logger::error("ERROR: Couldn't save to settings file " + myFile.getShortPath()); Logger::error("ERROR: Couldn't save to settings file " + myFile.getShortPath());
return false;
} }
} }

View File

@ -29,9 +29,9 @@ class KeyValueRepositoryConfigfile : public KeyValueRepository
std::map<string, Variant> load() override; std::map<string, Variant> load() override;
void save(const std::map<string, Variant>& values) override; bool save(const std::map<string, Variant>& values) override;
void save(const string& key, const Variant& value) override {} bool save(const string& key, const Variant& value) override { return false; }
void remove(const string& key) override {} void remove(const string& key) override {}

View File

@ -28,9 +28,9 @@ class KeyValueRepositoryNoop : public KeyValueRepository
return std::map<string, Variant>(); return std::map<string, Variant>();
} }
void save(const std::map<string, Variant>& values) override {} bool save(const std::map<string, Variant>& values) override { return false; }
void save(const string& key, const Variant& value) override {} bool save(const string& key, const Variant& value) override { return false; }
void remove(const string& key) override {} void remove(const string& key) override {}
}; };

View File

@ -0,0 +1,163 @@
//============================================================================
//
// 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 <istream>
#include <ostream>
#include <sstream>
#include <map>
#include "repository/KeyValueRepositoryPropertyFile.hxx"
#include "Logger.hxx"
namespace {
string 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 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('"');
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyValueRepositoryPropertyFile::KeyValueRepositoryPropertyFile(const FilesystemNode& node)
: myNode(node)
{}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::map<string, Variant> KeyValueRepositoryPropertyFile::load()
{
std::map<string, Variant> map;
if (!myNode.exists()) return map;
stringstream in;
try {
myNode.read(in);
}
catch (const runtime_error& err) {
Logger::error(err.what());
return map;
}
catch (...) {
return map;
}
// Loop reading properties
string key, value;
for(;;)
{
// Get the key associated with this property
key = readQuotedString(in);
// Make sure the stream is still okay
if(!in) return map;
// A null key signifies the end of the property list
if(key == "")
break;
// Get the value associated with this property
value = readQuotedString(in);
// Make sure the stream is still okay
if(!in)
return map;
map[key] = value;
}
return map;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool KeyValueRepositoryPropertyFile::save(const std::map<string, Variant>& values)
{
if (values.size() == 0) return true;
stringstream out;
for (auto& [key, value]: values) {
writeQuotedString(out, key);
out.put(' ');
writeQuotedString(out, value.toString());
out.put('\n');
}
writeQuotedString(out, "");
out.put('\n');
out.put('\n');
try {
myNode.write(out);
return true;
}
catch (const runtime_error& err) {
Logger::error(err.what());
return false;
}
catch (...)
{
return false;
}
}

View File

@ -0,0 +1,42 @@
//============================================================================
//
// 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 KEY_VALUE_REPOSITORY_PROPERTY_FILE_HXX
#define KEY_VALUE_REPOSITORY_PROPERTY_FILE_HXX
#include "repository/KeyValueRepository.hxx"
#include "FSNode.hxx"
#include "bspf.hxx"
class KeyValueRepositoryPropertyFile : public KeyValueRepository {
public:
KeyValueRepositoryPropertyFile(const FilesystemNode& node);
std::map<string, Variant> load() override;
bool save(const std::map<string, Variant>& values) override;
bool save(const string& key, const Variant& value) override { return false; }
void remove(const string& key) override {}
private:
const FilesystemNode& myNode;
};
#endif

View File

@ -34,14 +34,14 @@ std::map<string, Variant> AbstractKeyValueRepositorySqlite::load()
stmt.reset(); stmt.reset();
} }
catch (const SqliteError& err) { catch (const SqliteError& err) {
Logger::info(err.what()); Logger::error(err.what());
} }
return values; return values;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AbstractKeyValueRepositorySqlite::save(const std::map<string, Variant>& values) bool AbstractKeyValueRepositorySqlite::save(const std::map<string, Variant>& values)
{ {
try { try {
SqliteTransaction tx{database()}; SqliteTransaction tx{database()};
@ -54,23 +54,31 @@ void AbstractKeyValueRepositorySqlite::save(const std::map<string, Variant>& val
} }
tx.commit(); tx.commit();
return true;
} }
catch (const SqliteError& err) { catch (const SqliteError& err) {
Logger::info(err.what()); Logger::error(err.what());
return false;
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AbstractKeyValueRepositorySqlite::save(const string& key, const Variant& value) bool AbstractKeyValueRepositorySqlite::save(const string& key, const Variant& value)
{ {
try { try {
SqliteStatement& stmt{stmtInsert(key, value.toString())}; SqliteStatement& stmt{stmtInsert(key, value.toString())};
stmt.step(); stmt.step();
stmt.reset(); stmt.reset();
return true;
} }
catch (const SqliteError& err) { catch (const SqliteError& err) {
Logger::info(err.what()); Logger::error(err.what());
return false;
} }
} }
@ -84,6 +92,6 @@ void AbstractKeyValueRepositorySqlite::remove(const string& key)
stmt.reset(); stmt.reset();
} }
catch (const SqliteError& err) { catch (const SqliteError& err) {
Logger::info(err.what()); Logger::error(err.what());
} }
} }

View File

@ -12,9 +12,9 @@ class AbstractKeyValueRepositorySqlite : public KeyValueRepository
std::map<string, Variant> load() override; std::map<string, Variant> load() override;
void save(const std::map<string, Variant>& values) override; bool save(const std::map<string, Variant>& values) override;
void save(const string& key, const Variant& value) override; bool save(const string& key, const Variant& value) override;
void remove(const string& key) override; void remove(const string& key) override;

View File

@ -47,7 +47,7 @@ bool CompositeKeyValueRepositorySqlite::has(const string& key)
return rowCount > 0; return rowCount > 0;
} catch (const SqliteError& err) { } catch (const SqliteError& err) {
Logger::info(err.what()); Logger::error(err.what());
return false; return false;
} }
@ -64,7 +64,7 @@ void CompositeKeyValueRepositorySqlite::remove(const string& key)
.step(); .step();
} }
catch (const SqliteError& err) { catch (const SqliteError& err) {
Logger::info(err.what()); Logger::error(err.what());
} }
} }

View File

@ -40,7 +40,7 @@ bool SettingsDb::initialize()
myPropertyRepository->initialize(); myPropertyRepository->initialize();
} }
catch (const SqliteError& err) { catch (const SqliteError& err) {
Logger::info("sqlite DB " + databaseFileName() + " failed to initialize: " + err.what()); Logger::error("sqlite DB " + databaseFileName() + " failed to initialize: " + err.what());
myDb.reset(); myDb.reset();
mySettingsRepository.reset(); mySettingsRepository.reset();

View File

@ -75,11 +75,11 @@ void SqliteDatabase::initialize()
break; break;
case SQLITE_MISUSE: case SQLITE_MISUSE:
Logger::info("failed to checkpoint WAL on " + myDatabaseFile + " - WAL probably unavailable"); Logger::error("failed to checkpoint WAL on " + myDatabaseFile + " - WAL probably unavailable");
break; break;
default: default:
Logger::info("failed to checkpoint WAL on " + myDatabaseFile + " : " + sqlite3_errmsg(myHandle)); Logger::error("failed to checkpoint WAL on " + myDatabaseFile + " : " + sqlite3_errmsg(myHandle));
break; break;
} }
} }

View File

@ -45,7 +45,7 @@ void Properties::load(KeyValueRepository& repo)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Properties::save(KeyValueRepository& repo) const bool Properties::save(KeyValueRepository& repo) const
{ {
std::map<string, Variant> props; std::map<string, Variant> props;
@ -56,7 +56,7 @@ void Properties::save(KeyValueRepository& repo) const
props[ourPropertyNames[i]] = myProperties[i]; props[ourPropertyNames[i]] = myProperties[i];
} }
repo.save(props); return repo.save(props);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -84,7 +84,7 @@ class Properties
public: public:
void load(KeyValueRepository& repo); void load(KeyValueRepository& repo);
void save(KeyValueRepository& repo) const; bool 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

View File

@ -24,6 +24,7 @@
#include "Props.hxx" #include "Props.hxx"
#include "PropsSet.hxx" #include "PropsSet.hxx"
#include "repository/CompositeKeyValueRepositoryNoop.hxx" #include "repository/CompositeKeyValueRepositoryNoop.hxx"
#include "repository/KeyValueRepositoryPropertyFile.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropertiesSet::PropertiesSet() : myRepository{make_shared<CompositeKeyValueRepositoryNoop>()} {} PropertiesSet::PropertiesSet() : myRepository{make_shared<CompositeKeyValueRepositoryNoop>()} {}
@ -142,6 +143,8 @@ void PropertiesSet::insert(const Properties& properties, bool save)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PropertiesSet::loadPerROM(const FilesystemNode& rom, const string& md5) void PropertiesSet::loadPerROM(const FilesystemNode& rom, const string& md5)
{ {
Properties props;
// Handle ROM properties, do some error checking // Handle ROM properties, do some error checking
// Only add to the database when necessary // Only add to the database when necessary
bool toInsert = false; bool toInsert = false;
@ -149,14 +152,14 @@ 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"));
// CSTODO if (propsNode.exists()) {
#if 0 KeyValueRepositoryPropertyFile repo(propsNode);
if(propsNode.exists()) props.load(repo);
load(propsNode, false);
#endif insert(props, false);
}
// Next, make sure we have a valid md5 and name // Next, make sure we have a valid md5 and name
Properties props;
if(!getMD5(md5, props)) if(!getMD5(md5, props))
{ {
props.set(PropType::Cart_MD5, md5); props.set(PropType::Cart_MD5, md5);

View File

@ -36,6 +36,7 @@
#include "Widget.hxx" #include "Widget.hxx"
#include "Font.hxx" #include "Font.hxx"
#include "repository/KeyValueRepositoryPropertyFile.hxx"
#include "FrameBuffer.hxx" #include "FrameBuffer.hxx"
#include "TIASurface.hxx" #include "TIASurface.hxx"
#include "TIA.hxx" #include "TIA.hxx"
@ -1334,22 +1335,12 @@ void GameInfoDialog::exportCurrentPropertiesToDisk(const FilesystemNode& node)
{ {
saveProperties(); saveProperties();
// CSTODO KeyValueRepositoryPropertyFile repo(node);
#if 0
stringstream out;
out << myGameProperties;
try if (myGameProperties.save(repo))
{
node.write(out);
instance().frameBuffer().showTextMessage("ROM properties exported"); instance().frameBuffer().showTextMessage("ROM properties exported");
} else
catch(...)
{
instance().frameBuffer().showTextMessage("Error exporting ROM properties"); instance().frameBuffer().showTextMessage("Error exporting ROM properties");
}
#endif
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -