Harden VDF token parsing

Handle unterminated quoted strings as invalid tokens and stop returning raw pointers to entries in the game list.
This commit is contained in:
Marco Allegretti 2026-04-22 12:42:55 +02:00
parent 4dd0e17afb
commit eb177e0394
2 changed files with 27 additions and 11 deletions

View file

@ -75,7 +75,12 @@ public:
return {TokenType::CloseBrace, {}};
}
if (current == QLatin1Char('"')) {
return {TokenType::String, readQuotedString()};
bool terminated = false;
const QString text = readQuotedString(&terminated);
if (!terminated) {
return {TokenType::Invalid, text};
}
return {TokenType::String, text};
}
return {TokenType::String, readBareString()};
@ -106,14 +111,21 @@ private:
}
}
QString readQuotedString()
QString readQuotedString(bool *terminated)
{
QString result;
++m_pos;
if (terminated) {
*terminated = false;
}
while (m_pos < m_input.size()) {
const QChar current = m_input.at(m_pos++);
if (current == QLatin1Char('"')) {
if (terminated) {
*terminated = true;
}
return result;
}
if (current == QLatin1Char('\\') && m_pos < m_input.size()) {
@ -840,22 +852,24 @@ void GameLauncherProvider::clearLastLaunchError()
Q_EMIT lastLaunchErrorChanged();
}
GameLauncherProvider::GameEntry *GameLauncherProvider::findEntryByStorageId(const QString &storageId)
int GameLauncherProvider::findEntryIndexByStorageId(const QString &storageId) const
{
for (auto &entry : m_allGames) {
if (entry.storageId == storageId) {
return &entry;
for (int index = 0; index < m_allGames.size(); ++index) {
if (m_allGames.at(index).storageId == storageId) {
return index;
}
}
return nullptr;
return -1;
}
void GameLauncherProvider::markLaunchSucceeded(const QString &storageId, const QString &name)
{
if (auto *entry = findEntryByStorageId(storageId)) {
const int entryIndex = findEntryIndexByStorageId(storageId);
if (entryIndex >= 0) {
auto &entry = m_allGames[entryIndex];
const auto now = QDateTime::currentDateTime();
saveRecentTimestamp(entry->storageId, now);
entry->lastPlayed = now;
saveRecentTimestamp(entry.storageId, now);
entry.lastPlayed = now;
}
setPendingLaunch(name);

View file

@ -97,7 +97,9 @@ private:
void saveRecentTimestamp(const QString &storageId, const QDateTime &when);
void applyFilter();
void launchEntry(GameEntry &entry);
GameEntry *findEntryByStorageId(const QString &storageId);
// Returns the current m_allGames index for the storage id.
// Callers must re-lookup after any mutation that can rebuild or reorder the list.
int findEntryIndexByStorageId(const QString &storageId) const;
void markLaunchSucceeded(const QString &storageId, const QString &name);
void markLaunchFailed(const QString &name, const QString &error);
void setPendingLaunch(const QString &name);