From dae532d659b39fa70f625ec15057ca45d15d1ac5 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Thu, 12 Aug 2010 21:38:59 +0200 Subject: [PATCH] More work on the parser and Entry/Group data structures. --- src/core/Database.cpp | 67 +++++++++ src/core/Database.h | 16 +- src/core/Entry.cpp | 141 +++++++++++++++++- src/core/Entry.h | 58 +++++++- src/core/Group.cpp | 136 +++++++++++++++++ src/core/Group.h | 49 ++++++- src/core/Metadata.cpp | 54 ++++--- src/core/Metadata.h | 3 + src/core/Parser.cpp | 331 ++++++++++++++++++++++++++++++------------ src/core/Parser.h | 29 +++- src/core/TimeInfo.cpp | 69 +++++++++ src/core/TimeInfo.h | 27 ++++ src/core/Uuid.cpp | 6 +- src/core/Uuid.h | 1 + 14 files changed, 851 insertions(+), 136 deletions(-) diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 2c3f8d240..5045642c3 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -28,8 +28,75 @@ Database::Database(const QString& filename) } +Group* Database::rootGroup() +{ + return m_rootGroup; +} + +void Database::setRootGroup(Group* group) +{ + m_rootGroup = group; + group->setParent(this); +} + +Metadata* Database::metadata() +{ + return m_metadata; +} + void Database::open() { Parser* parser = new Parser(this); parser->parse(m_filename); } + +QImage Database::icon(int number) +{ + // TODO implement + return QImage(); +} + +QImage Database::customIcon(const Uuid& uuid) +{ + return m_customIcons[uuid]; +} + +Entry* Database::resolveEntry(const Uuid& uuid) +{ + return recFindEntry(uuid, m_rootGroup); +} + +Entry* Database::recFindEntry(const Uuid& uuid, Group* group) +{ + Q_FOREACH (Entry* entry, group->entries()) { + if (entry->uuid() == uuid) + return entry; + } + + Q_FOREACH (Group* child, group->children()) { + Entry* result = recFindEntry(uuid, child); + if (result) + return result; + } + + return 0; +} + +Group* Database::resolveGroup(const Uuid& uuid) +{ + return recFindGroup(uuid, m_rootGroup); +} + +Group* Database::recFindGroup(const Uuid& uuid, Group* group) +{ + if (group->uuid() == uuid) + return group; + + Q_FOREACH (Group* child, group->children()) { + Group* result = recFindGroup(uuid, child); + if (result) + return result; + } + + return 0; +} diff --git a/src/core/Database.h b/src/core/Database.h index 512cfcf1b..e196b9e06 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -27,20 +27,30 @@ class Metadata; -class Database +class Database : public QObject { + Q_OBJECT + public: Database(const QString& filename); Group* rootGroup(); + void setRootGroup(Group* group); + Metadata* metadata(); + static QImage icon(int number); + QImage customIcon(const Uuid& uuid); + Entry* resolveEntry(const Uuid& uuid); + Group* resolveGroup(const Uuid& uuid); private: void open(); + Entry* recFindEntry(const Uuid& uuid, Group* group); + Group* recFindGroup(const Uuid& uuid, Group* group); QString m_filename; Metadata* m_metadata; Group* m_rootGroup; - QHash customImages; - DbAttribute unhandledAttirbute; + QHash m_customIcons; + DbAttribute m_unhandledAttirbute; }; #endif // KEEPASSX_DATABASE_H diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 051b746a8..4e8d2d3f8 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -17,6 +17,145 @@ #include "Entry.h" -Entry::Entry() +#include "Group.h" + +Entry::Entry() : m_group(0) { } + +Uuid Entry::uuid() const +{ + return m_uuid; +} + +QImage Entry::icon() const +{ + // TODO implement +} + +QColor Entry::foregroundColor() const +{ + return m_foregroundColor; +} + +QColor Entry::backgroundColor() const +{ + return m_backgroundColor; +} + +QString Entry::overrideUrl() const +{ + return m_overrideUrl; +} + +TimeInfo Entry::timeInfo() const +{ + return m_timeInfo; +} + +bool Entry::autoTypeEnabled() const +{ + return m_autoTypeEnabled; +} + +int Entry::autoTypeObfuscation() const +{ + return m_autoTypeObfuscation; +} + +QString Entry::defaultAutoTypeSequence() const +{ + return m_defaultAutoTypeSequence; +} + +const QList& Entry::autoTypeAssociations() const +{ + return m_autoTypeAssociations; +} + +const QHash& Entry::attributes() const +{ + return m_attributes; +} + +const QHash& Entry::attachments() const +{ + return m_binaries; +} + +void Entry::setUuid(const Uuid& uuid) +{ + m_uuid = uuid; +} + +void Entry::setIcon(int iconNumber) +{ + m_iconNumber = iconNumber; + m_customIcon = Uuid(); +} + +void Entry::setIcon(const Uuid& uuid) +{ + m_iconNumber = 0; + m_customIcon = uuid; +} + +void Entry::setForegroundColor(const QColor& color) +{ + m_foregroundColor = color; +} + +void Entry::setBackgroundColor(const QColor& color) +{ + m_backgroundColor = color; +} + +void Entry::setOverrideUrl(const QString& url) +{ + m_overrideUrl = url; +} + +void Entry::setTimeInfo(const TimeInfo& timeInfo) +{ + m_timeInfo = timeInfo; +} + +void Entry::setAutoTypeEnabled(bool enable) +{ + m_autoTypeEnabled = enable; +} + +void Entry::setAutoTypeObfuscation(int obfuscation) +{ + m_autoTypeObfuscation = obfuscation; +} + +void Entry::setDefaultAutoTypeSequence(const QString& sequence) +{ + m_defaultAutoTypeSequence = sequence; +} + +void Entry::addAutoTypeAssociation(const AutoTypeAssociation& assoc) +{ + m_autoTypeAssociations << assoc; +} + +void Entry::addAttribute(const QString& key, const QString& value) +{ + m_attributes.insert(key, value); +} + +void Entry::addAttachment(const QString& key, const QByteArray& value) +{ + m_binaries.insert(key, value); +} + +void Entry::setGroup(Group* group) +{ + if (m_group) { + group->removeEntry(this); + } + group->addEntry(this); + m_group = group; + QObject::setParent(group); +} diff --git a/src/core/Entry.h b/src/core/Entry.h index dbf2f0f5b..7bb85cba1 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -18,21 +18,73 @@ #ifndef KEEPASSX_ENTRY_H #define KEEPASSX_ENTRY_H +#include +#include +#include +#include + +#include "TimeInfo.h" #include "Uuid.h" -#include +class Group; -class Entry +struct AutoTypeAssociation { + QString window; + QString sequence; +}; + +class Entry : public QObject +{ + Q_OBJECT + public: Entry(); + Uuid uuid() const; + QImage icon() const; + QColor foregroundColor() const; + QColor backgroundColor() const; + QString overrideUrl() const; + TimeInfo timeInfo() const; + bool autoTypeEnabled() const; + int autoTypeObfuscation() const; + QString defaultAutoTypeSequence() const; + const QList& autoTypeAssociations() const; + const QHash& attributes() const; + const QHash& attachments() const; + + void setUuid(const Uuid& uuid); + void setIcon(int iconNumber); + void setIcon(const Uuid& uuid); + void setForegroundColor(const QColor& color); + void setBackgroundColor(const QColor& color); + void setOverrideUrl(const QString& url); + void setTimeInfo(const TimeInfo& timeInfo); + void setAutoTypeEnabled(bool enable); + void setAutoTypeObfuscation(int obfuscation); + void setDefaultAutoTypeSequence(const QString& sequence); + void addAutoTypeAssociation(const AutoTypeAssociation& assoc); + void addAttribute(const QString& key, const QString& value); + void addAttachment(const QString& key, const QByteArray& value); + + void setGroup(Group* group); private: Uuid m_uuid; - int m_icon; + int m_iconNumber; Uuid m_customIcon; + QColor m_foregroundColor; + QColor m_backgroundColor; + QString m_overrideUrl; + TimeInfo m_timeInfo; + bool m_autoTypeEnabled; + int m_autoTypeObfuscation; + QString m_defaultAutoTypeSequence; + QList m_autoTypeAssociations; QHash m_attributes; QHash m_binaries; + + Group* m_group; }; #endif // KEEPASSX_ENTRY_H diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 0b75b2b90..51ab94493 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -20,3 +20,139 @@ #include "Group.h" +#include "Database.h" + +Group::Group() : m_parent(0) +{ +} + +Uuid Group::uuid() const +{ + return m_uuid; +} + +QString Group::name() const +{ + return m_name; +} + +QString Group::notes() const +{ + return m_notes; +} + +QImage Group::icon() const +{ + if (m_iconNumber == 0) + return m_db->customIcon(m_customIcon); + else + return Database::icon(m_iconNumber); +} + +TimeInfo Group::timeInfo() const +{ + return m_timeInfo; +} + +bool Group::isExpanded() const +{ + return m_isExpanded; +} + +QString Group::defaultAutoTypeSequence() const +{ + return m_defaultAutoTypeSequence; +} + +Entry* Group::lastTopVisibleEntry() const +{ + return m_lastTopVisibleEntry; +} + +void Group::setUuid(const Uuid& uuid) +{ + m_uuid = uuid; +} + +void Group::setName(const QString& name) +{ + m_name = name; +} + +void Group::setNotes(const QString& notes) +{ + m_notes = notes; +} + +void Group::setIcon(int iconNumber) +{ + m_iconNumber = iconNumber; + m_customIcon = Uuid(); +} + +void Group::setIcon(const Uuid& uuid) +{ + m_iconNumber = 0; + m_customIcon = uuid; +} + +void Group::setTimeInfo(const TimeInfo& timeInfo) +{ + m_timeInfo = timeInfo; +} + +void Group::setExpanded(bool expanded) +{ + m_isExpanded = expanded; +} + +void Group::setDefaultAutoTypeSequence(const QString& sequence) +{ + m_defaultAutoTypeSequence = sequence; +} + +void Group::setLastTopVisibleEntry(Entry* entry) +{ + m_lastTopVisibleEntry = entry; +} + +void Group::setParent(Group* parent) +{ + if (m_parent) { + m_parent->m_children.removeAll(this); + } + + m_db = parent->m_db; + QObject::setParent(parent); +} + +void Group::setParent(Database* db) +{ + if (m_db) { + m_db->setRootGroup(0); + } + + m_parent = 0; + m_db = db; + QObject::setParent(db); +} + +QList Group::children() const +{ + return m_children; +} + +QList Group::entries() const +{ + return m_entries; +} + +void Group::addEntry(Entry *entry) +{ + m_entries << entry; +} + +void Group::removeEntry(Entry* entry) +{ + m_entries.removeAll(entry); +} diff --git a/src/core/Group.h b/src/core/Group.h index b5a125db5..7802f7da2 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -18,19 +18,62 @@ #ifndef KEEPASSX_GROUP_H #define KEEPASSX_GROUP_H +#include + #include "Entry.h" +#include "TimeInfo.h" #include "Uuid.h" -class Group { +class Database; + +class Group : public QObject +{ + Q_OBJECT + +public: + Group(); + Uuid uuid() const; + QString name() const; + QString notes() const; + QImage icon() const; + TimeInfo timeInfo() const; + bool isExpanded() const; + QString defaultAutoTypeSequence() const; + Entry* lastTopVisibleEntry() const; + + void setUuid(const Uuid& uuid); + void setName(const QString& name); + void setNotes(const QString& notes); + void setIcon(int iconNumber); + void setIcon(const Uuid& uuid); + void setTimeInfo(const TimeInfo& timeInfo); + void setExpanded(bool expanded); + void setDefaultAutoTypeSequence(const QString& sequence); + void setLastTopVisibleEntry(Entry* entry); + + void setParent(Group* parent); + void setParent(Database* db); + + QList children() const; + QList entries() const; + void addEntry(Entry* entry); + void removeEntry(Entry* entry); + private: + Database* m_db; Uuid m_uuid; QString m_name; QString m_notes; - int m_icon; + int m_iconNumber; Uuid m_customIcon; + TimeInfo m_timeInfo; bool m_isExpanded; + QString m_defaultAutoTypeSequence; + Entry* m_lastTopVisibleEntry; + QList m_children; + QList m_entries; - QList m_children; + Group* m_parent; }; #endif // KEEPASSX_GROUP_H diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp index 0b1d17805..2f967b003 100644 --- a/src/core/Metadata.cpp +++ b/src/core/Metadata.cpp @@ -24,112 +24,117 @@ Metadata::Metadata() QString Metadata::generator() const { return m_generator; -}; +} QString Metadata::name() const { return m_name; -}; +} QDateTime Metadata::nameChanged() const { return m_nameChanged; -}; +} QString Metadata::description() const { return m_description; -}; +} QDateTime Metadata::descriptionChanged() const { return m_descriptionChanged; -}; +} QString Metadata::defaultUserName() const { return m_defaultUserName; -}; +} + +QDateTime Metadata::defaultUserNameChanged() const +{ + return m_defaultUserNameChanged; +} int Metadata::maintenanceHistoryDays() const { return m_maintenanceHistoryDays; -}; +} bool Metadata::protectTitle() const { return m_protectTitle; -}; +} bool Metadata::protectUsername() const { return m_protectUsername; -}; +} bool Metadata::protectPassword() const { return m_protectPassword; -}; +} bool Metadata::protectUrl() const { return m_protectUrl; -}; +} bool Metadata::protectNotes() const { return m_protectNotes; -}; +} bool Metadata::autoEnableVisualHiding() const { return m_autoEnableVisualHiding; -}; +} QHash Metadata::customIcons() const { return m_customIcons; -}; +} bool Metadata::recycleBinEnabled() const { return m_recycleBinEnabled; -}; +} Uuid Metadata::recycleBinUuid() const { return m_recycleBinUuid; -}; +} QDateTime Metadata::recycleBinChanged() const { return m_recycleBinChanged; -}; +} Uuid Metadata::entryTemplatesGroup() const { return m_entryTemplatesGroup; -}; +} QDateTime Metadata::entryTemplatesGroupChanged() const { return m_entryTemplatesGroupChanged; -}; +} Uuid Metadata::lastSelectedGroup() const { return m_lastSelectedGroup; -}; +} Uuid Metadata::lastTopVisibleGroup() const { return m_lastTopVisibleGroup; -}; +} QHash Metadata::customFields() const { return m_customFields; -}; +} void Metadata::setGenerator(const QString& value) { @@ -161,6 +166,11 @@ void Metadata::setDefaultUserName(const QString& value) m_defaultUserName = value; } +void Metadata::setDefaultUserNameChanged(const QDateTime& value) +{ + m_defaultUserNameChanged = value; +} + void Metadata::setMaintenanceHistoryDays(int value) { m_maintenanceHistoryDays = value; diff --git a/src/core/Metadata.h b/src/core/Metadata.h index be369e5e3..175f5c958 100644 --- a/src/core/Metadata.h +++ b/src/core/Metadata.h @@ -35,6 +35,7 @@ public: QString description() const; QDateTime descriptionChanged() const; QString defaultUserName() const; + QDateTime defaultUserNameChanged() const; int maintenanceHistoryDays() const; bool protectTitle() const; bool protectUsername() const; @@ -58,6 +59,7 @@ public: void setDescription(const QString& value); void setDescriptionChanged(const QDateTime& value); void setDefaultUserName(const QString& value); + void setDefaultUserNameChanged(const QDateTime& value); void setMaintenanceHistoryDays(int value); void setProtectTitle(bool value); void setProtectUsername(bool value); @@ -84,6 +86,7 @@ private: QString m_description; QDateTime m_descriptionChanged; QString m_defaultUserName; + QDateTime m_defaultUserNameChanged; int m_maintenanceHistoryDays; bool m_protectTitle; diff --git a/src/core/Parser.cpp b/src/core/Parser.cpp index 596da348a..099c19894 100644 --- a/src/core/Parser.cpp +++ b/src/core/Parser.cpp @@ -19,9 +19,13 @@ #include +#include "Database.h" +#include "Metadata.h" + Parser::Parser(Database* db) { m_db = db; + m_meta = db->metadata(); } bool Parser::parse(const QString& filename) @@ -30,16 +34,22 @@ bool Parser::parse(const QString& filename) file.open(QIODevice::ReadOnly | QIODevice::Text); m_xml.setDevice(&file); + m_tmpParent = new Group(); - if (m_xml.readNextStartElement()) { + if (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "KeePassFile") { parseKeePassFile(); } else { - m_xml.raiseError(tr("Invalid database file")); + raiseError(); } } + if (!m_tmpParent->children().isEmpty()) { + delete m_tmpParent; + raiseError(); + } + return !m_xml.error(); } @@ -47,7 +57,7 @@ void Parser::parseKeePassFile() { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "KeePassFile"); - while (m_xml.readNextStartElement()) { + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "Meta") { parseMeta(); } @@ -55,7 +65,7 @@ void Parser::parseKeePassFile() parseRoot(); } else { - m_xml.raiseError(tr("Invalid database file")); + m_xml.skipCurrentElement(); } } } @@ -64,30 +74,30 @@ void Parser::parseMeta() { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Meta"); - while (m_xml.readNextStartElement()) { + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "Generator") { - + m_meta->setGenerator(readString()); } else if (m_xml.name() == "DatabaseName") { - + m_meta->setName(readString()); } else if (m_xml.name() == "DatabaseNameChanged") { - + m_meta->setNameChanged(readDateTime()); } else if (m_xml.name() == "DatabaseDescription") { - + m_meta->setDescription(readString()); } else if (m_xml.name() == "DatabaseDescriptionChanged") { - + m_meta->setDescriptionChanged(readDateTime()); } else if (m_xml.name() == "DefaultUserName") { - + m_meta->setDefaultUserName(readString()); } else if (m_xml.name() == "DefaultUserNameChanged") { - + m_meta->setDefaultUserNameChanged(readDateTime()); } else if (m_xml.name() == "MaintenanceHistoryDays") { - + m_meta->setMaintenanceHistoryDays(readNumber()); } else if (m_xml.name() == "MemoryProtection") { parseMemoryProtection(); @@ -96,25 +106,25 @@ void Parser::parseMeta() parseCustomIcons(); } else if (m_xml.name() == "RecycleBinEnabled") { - + m_meta->setRecycleBinEnabled(readBool()); } else if (m_xml.name() == "RecycleBinUUID") { - + m_meta->setRecycleBinUuid(readUuid()); } else if (m_xml.name() == "RecycleBinChanged") { - + m_meta->setRecycleBinChanged(readDateTime()); } else if (m_xml.name() == "EntryTemplatesGroup") { - + m_meta->setEntryTemplatesGroup(readUuid()); } else if (m_xml.name() == "EntryTemplatesGroupChanged") { - + m_meta->setEntryTemplatesGroupChanged(readDateTime()); } else if (m_xml.name() == "LastSelectedGroup") { - + m_meta->setLastSelectedGroup(readUuid()); } else if (m_xml.name() == "LastTopVisibleGroup") { - + m_meta->setLastTopVisibleGroup(readUuid()); } else if (m_xml.name() == "CustomData") { parseCustomData(); @@ -129,24 +139,24 @@ void Parser::parseMemoryProtection() { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "MemoryProtection"); - while (m_xml.readNextStartElement()) { + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "ProtectTitle") { - + m_meta->setProtectTitle(readBool()); } else if (m_xml.name() == "ProtectUserName") { - + m_meta->setProtectUsername(readBool()); } else if (m_xml.name() == "ProtectPassword") { - + m_meta->setProtectPassword(readBool()); } else if (m_xml.name() == "ProtectURL") { - + m_meta->setProtectUrl(readBool()); } else if (m_xml.name() == "ProtectNotes") { - + m_meta->setProtectNotes(readBool()); } else if (m_xml.name() == "AutoEnableVisualHiding") { - + m_meta->setAutoEnableVisualHiding(readBool()); } else { m_xml.skipCurrentElement(); @@ -158,7 +168,7 @@ void Parser::parseCustomIcons() { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomIcons"); - while (m_xml.readNextStartElement()) { + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "Icon") { parseIcon(); } @@ -172,12 +182,15 @@ void Parser::parseIcon() { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Icon"); - while (m_xml.readNextStartElement()) { + Uuid uuid; + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "UUID") { - + uuid = readUuid(); } else if (m_xml.name() == "Data") { - + QImage image; + image.loadFromData(readBinary()); + m_meta->addCustomIcon(uuid, image); } else { m_xml.skipCurrentElement(); @@ -196,12 +209,15 @@ void Parser::parseRoot() { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Root"); - while (m_xml.readNextStartElement()) { + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "Group") { - parseGroup(); + Group* rootGroup = parseGroup(); + if (rootgroup) { + rootGroup->setParent(m_db); + } } else if (m_xml.name() == "DeletedObjects") { - // ????????????????? + // TODO implement } else { m_xml.skipCurrentElement(); @@ -209,87 +225,125 @@ void Parser::parseRoot() } } -void Parser::parseGroup() +Group* Parser::parseGroup() { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Group"); - while (m_xml.readNextStartElement()) { + Group* group = 0; + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "UUID") { - + Uuid uuid = readUuid(); + if (uuid.isNull()) { + raiseError(); + } + else { + group = getGroup(uuid); + } } else if (m_xml.name() == "Name") { - + group->setName(readString()); } else if (m_xml.name() == "Notes") { - + group->setNotes(readString()); } else if (m_xml.name() == "IconID") { - + int iconId = readNumber(); + if (iconId != 0) + group->setIcon(iconId); + } + else if (m_xml.name() == "CustomIconUUID") { + Uuid uuid = readUuid(); + if (!uuid.isNull()) { + group->setIcon(uuid); + } } else if (m_xml.name() == "Times") { - parseTimes(); + group->setTimeInfo(parseTimes()); } else if (m_xml.name() == "IsExpanded") { - + group->setExpanded(readBool()); } else if (m_xml.name() == "DefaultAutoTypeSequence") { - + group->setDefaultAutoTypeSequence(readString()); } else if (m_xml.name() == "EnableAutoType") { - + // TODO implement } else if (m_xml.name() == "EnableSearching") { - + // TODO implement } else if (m_xml.name() == "LastTopVisibleEntry") { - + Uuid uuid = readUuid(); + if (uuid.isNull()) + group->setLastTopVisibleEntry(0); + else + group->setLastTopVisibleEntry(getEntry(uuid)); } else if (m_xml.name() == "Group") { - parseGroup(); + Group* newGroup = parseGroup(); + if (newGroup) { + newGroup->setParent(group); + } } else if (m_xml.name() == "Entry") { - parseEntry(); + Entry* newEntry = parseEntry(); + if (newEntry) { + newEntry->setGroup(group); + } } else { m_xml.skipCurrentElement(); } } + + return group; } -void Parser::parseEntry() +Entry* Parser::parseEntry() { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Entry"); - while (m_xml.readNextStartElement()) { + Entry* entry = 0; + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "UUID") { - + Uuid uuid = readUuid(); + if (uuid.isNull()) { + raiseError(); + } + else { + entry = getEntry(uuid); + } } else if (m_xml.name() == "IconID") { - + int iconId = readNumber(); + if (iconId != 0) + entry->setIcon(iconId); } else if (m_xml.name() == "CustomIconUUID") { - + Uuid uuid = readUuid(); + if (!uuid.isNull()) + entry->setIcon(uuid); } else if (m_xml.name() == "ForegroundColor") { - + entry->setForegroundColor(readColor()); } else if (m_xml.name() == "BackgroundColor") { - + entry->setBackgroundColor(readColor()); } else if (m_xml.name() == "OverrideURL") { - + entry->setOverrideUrl(readString()); } else if (m_xml.name() == "Times") { - parseTimes(); + entry->setTimeInfo(parseTimes()); } else if (m_xml.name() == "String") { - parseEntryString(); + parseEntryString(entry); } else if (m_xml.name() == "Binary") { - parseEntryBinary(); + parseEntryBinary(entry); } else if (m_xml.name() == "AutoType") { - parseAutoType(); + parseAutoType(entry); } else if (m_xml.name() == "History") { parseEntryHistory(); @@ -300,16 +354,17 @@ void Parser::parseEntry() } } -void Parser::parseEntryString() +void Parser::parseEntryString(Entry *entry) { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "String"); - while (m_xml.readNextStartElement()) { + QString key; + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "Key") { - + key = readString(); } else if (m_xml.name() == "Value") { - + entry->addAttribute(key, readString()); } else { m_xml.skipCurrentElement(); @@ -317,16 +372,17 @@ void Parser::parseEntryString() } } -void Parser::parseEntryBinary() +void Parser::parseEntryBinary(Entry *entry) { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Binary"); - while (m_xml.readNextStartElement()) { + QString key; + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "Key") { - + key = readString(); } else if (m_xml.name() == "Value") { - + entry->addAttachment(key, readBinary()); } else { m_xml.skipCurrentElement(); @@ -334,19 +390,22 @@ void Parser::parseEntryBinary() } } -void Parser::parseAutoType() +void Parser::parseAutoType(Entry* entry) { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "AutoType"); - while (m_xml.readNextStartElement()) { + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "Enabled") { - + entry->setAutoTypeEnabled(readBool()); } else if (m_xml.name() == "DataTransferObfuscation") { - + entry->setAutoTypeObfuscation(readNumber()); + } + else if (m_xml.name() == "DefaultSequence") { + entry->setDefaultAutoTypeSequence(readString()); } else if (m_xml.name() == "Association") { - parseAutoTypeAssoc(); + parseAutoTypeAssoc(entry); } else { m_xml.skipCurrentElement(); @@ -354,16 +413,18 @@ void Parser::parseAutoType() } } -void Parser::parseAutoTypeAssoc() +void Parser::parseAutoTypeAssoc(Entry *entry) { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Association"); - while (m_xml.readNextStartElement()) { + AutoTypeAssociation assoc; + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "Window") { - + assoc.window = readString(); } else if (m_xml.name() == "KeystrokeSequence") { - + assoc.sequence = readString(); + entry->addAutoTypeAssociation(assoc); } else { m_xml.skipCurrentElement(); @@ -375,9 +436,9 @@ void Parser::parseEntryHistory() { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "History"); - while (m_xml.readNextStartElement()) { + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "Entry") { - parseEntry(); + // TODO implement } else { m_xml.skipCurrentElement(); @@ -385,36 +446,39 @@ void Parser::parseEntryHistory() } } -void Parser::parseTimes() +TimeInfo Parser::parseTimes() { Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Times"); - while (m_xml.readNextStartElement()) { + TimeInfo timeInfo; + while (!m_xml.error() && m_xml.readNextStartElement()) { if (m_xml.name() == "LastModificationTime") { - + timeInfo.setLastModificationTime(readDateTime()); } else if (m_xml.name() == "CreationTime") { - + timeInfo.setCreationTime(readDateTime()); } else if (m_xml.name() == "LastAccessTime") { - + timeInfo.setLastAccessTime(readDateTime()); } else if (m_xml.name() == "ExpiryTime") { - + timeInfo.setExpiryTime(readDateTime()); } else if (m_xml.name() == "Expires") { - + timeInfo.setExpires(readBool()); } else if (m_xml.name() == "UsageCount") { - + timeInfo.setUsageCount(readNumber()); } else if (m_xml.name() == "LocationChanged") { - + timeInfo.setLocationChanged(readDateTime()); } else { m_xml.skipCurrentElement(); } } + + return timeInfo; } QString Parser::readString() @@ -433,7 +497,7 @@ bool Parser::readBool() return false; } else { - // TODO error + raiseError(); } } @@ -443,23 +507,102 @@ QDateTime Parser::readDateTime() QDateTime dt = QDateTime::fromString(str, Qt::ISODate); if (!dt.isValid()) { - // TODO error + raiseError(); } return dt; } -int Parser::readInt() +QColor Parser::readColor() { - // TODO + QString colorStr = readString(); + if (colorStr.length() != 7 || colorStr[0] != '#') { + raiseError(); + return QColor(); + } + + QColor color; + for (int i=0; i<= 2; i++) { + QString rgbPartStr = colorStr.mid(1 + 2*i, 2); + bool ok; + int rgbPart = rgbPartStr.toInt(&ok); + if (!ok || rgbPart > 255) { + raiseError(); + return QColor(); + } + + if (i == 0) { + color.setRed(rgbPart); + } + else if (i == 1) { + color.setGreen(rgbPart); + } + else { + color.setBlue(rgbPart); + } + } + + return color; +} + +int Parser::readNumber() +{ + bool ok; + int result = readString().toInt(&ok); + if (!ok) { + raiseError(); + } + return result; } Uuid Parser::readUuid() { - // TODO + QByteArray uuidBin = readBinary(); + if (uuidBin.length() != Uuid::length) { + raiseError(); + return Uuid(); + } + else { + return Uuid(readBinary()); + } } QByteArray Parser::readBinary() { - // TODO + return QByteArray::fromBase64(readString().toAscii()); +} + +Group* Parser::getGroup(const Uuid& uuid) +{ + Q_FOREACH (Group* group, m_groups) { + if (group->uuid() == uuid) { + return group; + } + } + + Group* group = new Group(); + group->setUuid(uuid); + group->setParent(m_tmpParent); + m_groups << group; + return group; +} + +Entry* Parser::getEntry(const Uuid& uuid) +{ + Q_FOREACH (Entry* entry, m_entries) { + if (entry->uuid() == uuid) { + return entry; + } + } + + Entry* entry = new Entry(); + entry->setUuid(uuid); + entry->setGroup(m_tmpParent); + m_entries << entry; + return entry; +} + +void Parser::raiseError() +{ + m_xml.raiseError(tr("Invalid database file")); } diff --git a/src/core/Parser.h b/src/core/Parser.h index a5f9dcd4a..5b22185b6 100644 --- a/src/core/Parser.h +++ b/src/core/Parser.h @@ -20,10 +20,14 @@ #include #include +#include #include "Uuid.h" class Database; +class Entry; +class Group; +class Metadata; class Parser : public QObject { @@ -41,24 +45,33 @@ private: void parseIcon(); void parseCustomData(); void parseRoot(); - void parseGroup(); - void parseEntry(); - void parseEntryString(); - void parseEntryBinary(); - void parseAutoType(); - void parseAutoTypeAssoc(); + Group* parseGroup(); + Entry* parseEntry(); + void parseEntryString(Entry* entry); + void parseEntryBinary(Entry* entry); + void parseAutoType(Entry* entry); + void parseAutoTypeAssoc(Entry* entry); void parseEntryHistory(); - void parseTimes(); + TimeInfo parseTimes(); QString readString(); bool readBool(); QDateTime readDateTime(); - int readInt(); + QColor readColor(); + int readNumber(); Uuid readUuid(); QByteArray readBinary(); + Group* getGroup(const Uuid& uuid); + Entry* getEntry(const Uuid& uuid); + void raiseError(); + QXmlStreamReader m_xml; Database* m_db; + Metadata* m_meta; + Group* m_tmpParent; + QList m_groups; + QList m_entries; }; #endif // KEEPASSX_PARSER_H diff --git a/src/core/TimeInfo.cpp b/src/core/TimeInfo.cpp index 7a412efed..5fa0576e3 100644 --- a/src/core/TimeInfo.cpp +++ b/src/core/TimeInfo.cpp @@ -20,3 +20,72 @@ TimeInfo::TimeInfo() { } + +QDateTime TimeInfo::lastModificationTime() const +{ + return m_lastModificationTime; +} + +QDateTime TimeInfo::creationTime() const +{ + return m_creationTime; +} + +QDateTime TimeInfo::lastAccessTime() const +{ + return m_lastAccessTime; +} + +QDateTime TimeInfo::expiryTime() const +{ + return m_expiryTime; +} + +bool TimeInfo::expires() const +{ + return m_expires; +} + +int TimeInfo::usageCount() const +{ + return m_usageCount; +} +QDateTime TimeInfo::locationChanged() const +{ + return m_locationChanged; +} + +void TimeInfo::setLastModificationTime(const QDateTime& dateTime) +{ + m_lastModificationTime = dateTime; +} + +void TimeInfo::setCreationTime(const QDateTime& dateTime) +{ + m_creationTime = dateTime; +} + +void TimeInfo::setLastAccessTime(const QDateTime& dateTime) +{ + m_lastAccessTime = dateTime; +} + +void TimeInfo::setExpiryTime(const QDateTime& dateTime) +{ + m_expiryTime = dateTime; +} + +void TimeInfo::setExpires(bool expires) +{ + m_expires = expires; +} + +void TimeInfo::setUsageCount(int count) +{ + m_usageCount = count; +} + +void TimeInfo::setLocationChanged(const QDateTime& dateTime) +{ + m_locationChanged = dateTime; +} diff --git a/src/core/TimeInfo.h b/src/core/TimeInfo.h index 27eab26dc..079c5fbbe 100644 --- a/src/core/TimeInfo.h +++ b/src/core/TimeInfo.h @@ -18,10 +18,37 @@ #ifndef KEEPASSX_DBTIMEINFO_H #define KEEPASSX_DBTIMEINFO_H +#include + class TimeInfo { public: TimeInfo(); + + QDateTime lastModificationTime() const; + QDateTime creationTime() const; + QDateTime lastAccessTime() const; + QDateTime expiryTime() const; + bool expires() const; + int usageCount() const; + QDateTime locationChanged() const; + + void setLastModificationTime(const QDateTime& dateTime); + void setCreationTime(const QDateTime& dateTime); + void setLastAccessTime(const QDateTime& dateTime); + void setExpiryTime(const QDateTime& dateTime); + void setExpires(bool expires); + void setUsageCount(int count); + void setLocationChanged(const QDateTime& dateTime); + +private: + QDateTime m_lastModificationTime; + QDateTime m_creationTime; + QDateTime m_lastAccessTime; + QDateTime m_expiryTime; + bool m_expires; + int m_usageCount; + QDateTime m_locationChanged; }; #endif // KEEPASSX_DBTIMEINFO_H diff --git a/src/core/Uuid.cpp b/src/core/Uuid.cpp index 80a8abdd2..8757ab2b2 100644 --- a/src/core/Uuid.cpp +++ b/src/core/Uuid.cpp @@ -17,11 +17,13 @@ #include "Uuid.h" -Uuid::Uuid() : m_data(16, 0) +const int Uuid::length = 16; + +Uuid::Uuid() : m_data(length, 0) { } -Uuid::Uuid(bool generate) : m_data(16, 0) +Uuid::Uuid(bool generate) : m_data(length, 0) { if (generate) { while (isNull()) { diff --git a/src/core/Uuid.h b/src/core/Uuid.h index 4cbb09964..d177e0687 100644 --- a/src/core/Uuid.h +++ b/src/core/Uuid.h @@ -32,6 +32,7 @@ public: bool isNull() const; bool operator==(const Uuid& other) const; bool operator!=(const Uuid& other) const; + static const int length; private: QByteArray m_data;