diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index bdd053e98..156dd3d9e 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -135,14 +135,24 @@ const QList& Entry::autoTypeAssociations() const return m_autoTypeAssociations; } -const QHash& Entry::attributes() const +const QList& Entry::attributes() const { - return m_attributes; + return m_attributesKeys; } -const QHash& Entry::attachments() const +QString Entry::attributeValue(const QString& key) const { - return m_binaries; + return m_attributes.value(key); +} + +const QList& Entry::attachments() const +{ + return m_binariesKeys; +} + +QByteArray Entry::attachmentValue(const QString& key) const +{ + return m_binaries.value(key); } bool Entry::isAttributeProtected(const QString& key) const @@ -254,7 +264,12 @@ void Entry::addAutoTypeAssociation(const AutoTypeAssociation& assoc) void Entry::setAttribute(const QString& key, const QString& value, bool protect) { + if (!m_attributes.contains(key)) { + m_attributesKeys.append(key); + } + m_attributes.insert(key, value); + if (protect) { m_protectedAttributes.insert(key); } @@ -271,13 +286,19 @@ void Entry::removeAttribute(const QString& key) { Q_ASSERT(!isDefaultAttribute(key)); + m_attributesKeys.removeOne(key); m_attributes.remove(key); m_protectedAttributes.remove(key); } void Entry::setAttachment(const QString& key, const QByteArray& value, bool protect) { + if (!m_binaries.contains(key)) { + m_binariesKeys.append(key); + } + m_binaries.insert(key, value); + if (protect) { m_protectedAttachments.insert(key); } @@ -288,6 +309,7 @@ void Entry::setAttachment(const QString& key, const QByteArray& value, bool prot void Entry::removeAttachment(const QString& key) { + m_binariesKeys.removeOne(key); m_binaries.remove(key); m_protectedAttachments.remove(key); } diff --git a/src/core/Entry.h b/src/core/Entry.h index c910e548d..17abc99b4 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -60,8 +60,10 @@ public: int autoTypeObfuscation() const; QString defaultAutoTypeSequence() const; const QList& autoTypeAssociations() const; - const QHash& attributes() const; - const QHash& attachments() const; + const QList& attributes() const; + QString attributeValue(const QString& key) const; + const QList& attachments() const; + QByteArray attachmentValue(const QString& key) const; bool isAttributeProtected(const QString& key) const; bool isAttachmentProtected(const QString& key) const; QString title() const; @@ -121,7 +123,9 @@ private: QString m_defaultAutoTypeSequence; QList m_autoTypeAssociations; QHash m_attributes; + QList m_attributesKeys; QHash m_binaries; + QList m_binariesKeys; QSet m_protectedAttributes; QSet m_protectedAttachments; diff --git a/src/format/KeePass2XmlWriter.cpp b/src/format/KeePass2XmlWriter.cpp index 075c9d710..4d85d8d66 100644 --- a/src/format/KeePass2XmlWriter.cpp +++ b/src/format/KeePass2XmlWriter.cpp @@ -253,7 +253,7 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry) writeString("Tags", entry->tags()); writeTimes(entry->timeInfo()); - Q_FOREACH (const QString& key, entry->attributes().keys()) { + Q_FOREACH (const QString& key, entry->attributes()) { m_xml.writeStartElement("String"); bool protect = ( ((key == "Title") && m_meta->protectTitle()) || @@ -271,11 +271,11 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry) if (protect) { m_xml.writeAttribute("Protected", "True"); - QByteArray rawData = m_randomStream->process(entry->attributes().value(key).toUtf8()); + QByteArray rawData = m_randomStream->process(entry->attributeValue(key).toUtf8()); value = QString::fromAscii(rawData.toBase64()); } else { - value = entry->attributes().value(key); + value = entry->attributeValue(key); } m_xml.writeCharacters(value); @@ -284,7 +284,7 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry) m_xml.writeEndElement(); } - Q_FOREACH (const QString& key, entry->attachments().keys()) { + Q_FOREACH (const QString& key, entry->attachments()) { m_xml.writeStartElement("Binary"); bool protect = entry->isAttachmentProtected(key) && m_randomStream; @@ -296,11 +296,11 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry) if (protect) { m_xml.writeAttribute("Protected", "True"); - QByteArray rawData = m_randomStream->process(entry->attachments().value(key)); + QByteArray rawData = m_randomStream->process(entry->attachmentValue(key)); value = QString::fromAscii(rawData.toBase64()); } else { - value = entry->attachments().value(key); + value = entry->attachmentValue(key); } m_xml.writeCharacters(value); diff --git a/tests/TestKeePass2Reader.cpp b/tests/TestKeePass2Reader.cpp index 67fbdcacf..70bf0a0bf 100644 --- a/tests/TestKeePass2Reader.cpp +++ b/tests/TestKeePass2Reader.cpp @@ -79,8 +79,8 @@ void TestKeePass2Reader::testProtectedStrings() QCOMPARE(entry->title(), QString("Sample Entry")); QCOMPARE(entry->username(), QString("Protected User Name")); QCOMPARE(entry->password(), QString("ProtectedPassword")); - QCOMPARE(entry->attributes().value("TestProtected"), QString("ABC")); - QCOMPARE(entry->attributes().value("TestUnprotected"), QString("DEF")); + QCOMPARE(entry->attributeValue("TestProtected"), QString("ABC")); + QCOMPARE(entry->attributeValue("TestUnprotected"), QString("DEF")); QVERIFY(!db->metadata()->protectTitle()); QVERIFY(db->metadata()->protectUsername()); diff --git a/tests/TestKeePass2Writer.cpp b/tests/TestKeePass2Writer.cpp index bda8b2735..fd93ef0b6 100644 --- a/tests/TestKeePass2Writer.cpp +++ b/tests/TestKeePass2Writer.cpp @@ -75,7 +75,7 @@ void TestKeePass2Writer::testProtectedAttributes() { QCOMPARE(m_dbTest->rootGroup()->entries().size(), 1); Entry* entry = m_dbTest->rootGroup()->entries().at(0); - QCOMPARE(entry->attributes().value("test"), QString("protectedTest")); + QCOMPARE(entry->attributeValue("test"), QString("protectedTest")); QCOMPARE(entry->isAttributeProtected("test"), true); } diff --git a/tests/TestKeePass2XmlReader.cpp b/tests/TestKeePass2XmlReader.cpp index 12b2dafd2..56e513dd6 100644 --- a/tests/TestKeePass2XmlReader.cpp +++ b/tests/TestKeePass2XmlReader.cpp @@ -214,19 +214,24 @@ void TestKeePass2XmlReader::testEntry1() QCOMPARE(ti.usageCount(), 8); QCOMPARE(ti.locationChanged(), genDT(2010, 8, 25, 16, 13, 54)); - QHash attrs = entry->attributes(); - QCOMPARE(attrs.take("Notes"), QString("Notes")); - QCOMPARE(attrs.take("Password"), QString("Password")); - QCOMPARE(attrs.take("Title"), QString("Sample Entry 1")); - QCOMPARE(attrs.take("URL"), QString("")); - QCOMPARE(attrs.take("UserName"), QString("User Name")); + QList attrs = entry->attributes(); + QCOMPARE(entry->attributeValue("Notes"), QString("Notes")); + QVERIFY(attrs.removeOne("Notes")); + QCOMPARE(entry->attributeValue("Password"), QString("Password")); + QVERIFY(attrs.removeOne("Password")); + QCOMPARE(entry->attributeValue("Title"), QString("Sample Entry 1")); + QVERIFY(attrs.removeOne("Title")); + QCOMPARE(entry->attributeValue("URL"), QString("")); + QVERIFY(attrs.removeOne("URL")); + QCOMPARE(entry->attributeValue("UserName"), QString("User Name")); + QVERIFY(attrs.removeOne("UserName")); QVERIFY(attrs.isEmpty()); - QCOMPARE(entry->title(), entry->attributes().value("Title")); - QCOMPARE(entry->url(), entry->attributes().value("URL")); - QCOMPARE(entry->username(), entry->attributes().value("UserName")); - QCOMPARE(entry->password(), entry->attributes().value("Password")); - QCOMPARE(entry->notes(), entry->attributes().value("Notes")); + QCOMPARE(entry->title(), entry->attributeValue("Title")); + QCOMPARE(entry->url(), entry->attributeValue("URL")); + QCOMPARE(entry->username(), entry->attributeValue("UserName")); + QCOMPARE(entry->password(), entry->attributeValue("Password")); + QCOMPARE(entry->notes(), entry->attributeValue("Notes")); QCOMPARE(entry->attachments().size(), 0); QCOMPARE(entry->autoTypeEnabled(), false); @@ -253,18 +258,25 @@ void TestKeePass2XmlReader::testEntry2() const TimeInfo ti = entry->timeInfo(); QCOMPARE(ti.usageCount(), 7); - QHash attrs = entry->attributes(); - QCOMPARE(attrs.take("CustomString"), QString("isavalue")); - QCOMPARE(attrs.take("Notes"), QString("")); - QCOMPARE(attrs.take("Password"), QString("Jer60Hz8o9XHvxBGcRqT")); - QCOMPARE(attrs.take("Protected String"), QString("y")); // TODO should have a protection attribute - QCOMPARE(attrs.take("Title"), QString("Sample Entry 2")); - QCOMPARE(attrs.take("URL"), QString("http://www.keepassx.org/")); - QCOMPARE(attrs.take("UserName"), QString("notDEFUSERNAME")); + QList attrs = entry->attributes(); + QCOMPARE(entry->attributeValue("CustomString"), QString("isavalue")); + QVERIFY(attrs.removeOne("CustomString")); + QCOMPARE(entry->attributeValue("Notes"), QString("")); + QVERIFY(attrs.removeOne("Notes")); + QCOMPARE(entry->attributeValue("Password"), QString("Jer60Hz8o9XHvxBGcRqT")); + QVERIFY(attrs.removeOne("Password")); + QCOMPARE(entry->attributeValue("Protected String"), QString("y")); // TODO should have a protection attribute + QVERIFY(attrs.removeOne("Protected String")); + QCOMPARE(entry->attributeValue("Title"), QString("Sample Entry 2")); + QVERIFY(attrs.removeOne("Title")); + QCOMPARE(entry->attributeValue("URL"), QString("http://www.keepassx.org/")); + QVERIFY(attrs.removeOne("URL")); + QCOMPARE(entry->attributeValue("UserName"), QString("notDEFUSERNAME")); + QVERIFY(attrs.removeOne("UserName")); QVERIFY(attrs.isEmpty()); QCOMPARE(entry->attachments().size(), 1); - QCOMPARE(QString(entry->attachments().value("testattach.txt")), QString("42")); + QCOMPARE(QString(entry->attachmentValue("testattach.txt")), QString("42")); QCOMPARE(entry->autoTypeEnabled(), true); QCOMPARE(entry->autoTypeObfuscation(), 1);