2010-08-07 13:10:44 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 2 or (at your option)
|
|
|
|
|
* version 3 of the License.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
#include "KeePass2XmlReader.h"
|
2010-08-07 13:10:44 +00:00
|
|
|
|
2013-10-03 13:18:16 +00:00
|
|
|
#include <QBuffer>
|
|
|
|
|
#include <QFile>
|
2010-08-07 13:10:44 +00:00
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
#include "core/Database.h"
|
2010-09-22 22:21:36 +00:00
|
|
|
#include "core/DatabaseIcons.h"
|
2011-07-08 11:57:02 +00:00
|
|
|
#include "core/Group.h"
|
2010-08-31 12:39:35 +00:00
|
|
|
#include "core/Metadata.h"
|
2012-05-02 09:06:24 +00:00
|
|
|
#include "core/Tools.h"
|
2011-07-06 22:15:52 +00:00
|
|
|
#include "format/KeePass2RandomStream.h"
|
2012-04-21 14:45:46 +00:00
|
|
|
#include "streams/QtIOCompressor"
|
2010-08-12 19:38:59 +00:00
|
|
|
|
2013-04-14 12:31:19 +00:00
|
|
|
typedef QPair<QString, QString> StringPair;
|
|
|
|
|
|
2010-08-31 14:18:45 +00:00
|
|
|
KeePass2XmlReader::KeePass2XmlReader()
|
2012-06-29 12:15:16 +00:00
|
|
|
: m_randomStream(Q_NULLPTR)
|
|
|
|
|
, m_db(Q_NULLPTR)
|
|
|
|
|
, m_meta(Q_NULLPTR)
|
2013-06-30 12:43:02 +00:00
|
|
|
, m_error(false)
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-06 22:15:52 +00:00
|
|
|
void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2RandomStream* randomStream)
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
2013-06-30 12:43:02 +00:00
|
|
|
m_error = false;
|
|
|
|
|
m_errorStr.clear();
|
|
|
|
|
|
2012-01-06 19:03:13 +00:00
|
|
|
m_xml.clear();
|
2010-08-31 14:18:45 +00:00
|
|
|
m_xml.setDevice(device);
|
|
|
|
|
|
2010-09-25 10:41:00 +00:00
|
|
|
m_db = db;
|
2010-08-31 14:18:45 +00:00
|
|
|
m_meta = m_db->metadata();
|
2012-04-11 13:57:11 +00:00
|
|
|
m_meta->setUpdateDatetime(false);
|
|
|
|
|
|
2011-07-06 22:15:52 +00:00
|
|
|
m_randomStream = randomStream;
|
2012-09-25 20:33:36 +00:00
|
|
|
m_headerHash.clear();
|
2010-08-07 13:10:44 +00:00
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
m_tmpParent = new Group();
|
2010-08-07 13:10:44 +00:00
|
|
|
|
2013-04-20 17:01:43 +00:00
|
|
|
bool rootGroupParsed = false;
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
if (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "KeePassFile") {
|
2013-04-20 17:01:43 +00:00
|
|
|
rootGroupParsed = parseKeePassFile();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-20 17:01:43 +00:00
|
|
|
if (!m_xml.error() && !rootGroupParsed) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("No root group");
|
2013-04-20 17:01:43 +00:00
|
|
|
}
|
|
|
|
|
|
2012-04-11 16:46:23 +00:00
|
|
|
if (!m_xml.error()) {
|
|
|
|
|
if (!m_tmpParent->children().isEmpty()) {
|
|
|
|
|
qWarning("KeePass2XmlReader::readDatabase: found %d invalid group reference(s)",
|
|
|
|
|
m_tmpParent->children().size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_tmpParent->entries().isEmpty()) {
|
|
|
|
|
qWarning("KeePass2XmlReader::readDatabase: found %d invalid entry reference(s)",
|
|
|
|
|
m_tmpParent->children().size());
|
|
|
|
|
}
|
2010-08-12 19:38:59 +00:00
|
|
|
}
|
|
|
|
|
|
2012-04-21 14:45:46 +00:00
|
|
|
QSet<QString> poolKeys = m_binaryPool.keys().toSet();
|
|
|
|
|
QSet<QString> entryKeys = m_binaryMap.keys().toSet();
|
|
|
|
|
QSet<QString> unmappedKeys = entryKeys - poolKeys;
|
|
|
|
|
QSet<QString> unusedKeys = poolKeys - entryKeys;
|
|
|
|
|
|
|
|
|
|
if (!unmappedKeys.isEmpty()) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Unmapped keys left.");
|
2012-04-21 14:45:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_xml.error()) {
|
|
|
|
|
Q_FOREACH (const QString& key, unusedKeys) {
|
|
|
|
|
qWarning("KeePass2XmlReader::readDatabase: found unused key \"%s\"", qPrintable(key));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QHash<QString, QPair<Entry*, QString> >::const_iterator i;
|
|
|
|
|
for (i = m_binaryMap.constBegin(); i != m_binaryMap.constEnd(); ++i) {
|
2012-04-22 10:29:18 +00:00
|
|
|
const QPair<Entry*, QString>& target = i.value();
|
2012-04-21 14:45:46 +00:00
|
|
|
target.first->attachments()->set(target.second, m_binaryPool[i.key()]);
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-11 13:57:11 +00:00
|
|
|
m_meta->setUpdateDatetime(true);
|
2012-04-23 15:02:09 +00:00
|
|
|
|
2012-04-22 10:29:18 +00:00
|
|
|
QHash<Uuid, Group*>::const_iterator iGroup;
|
|
|
|
|
for (iGroup = m_groups.constBegin(); iGroup != m_groups.constEnd(); ++iGroup) {
|
|
|
|
|
iGroup.value()->setUpdateTimeinfo(true);
|
2012-04-11 16:00:28 +00:00
|
|
|
}
|
2012-04-11 13:57:11 +00:00
|
|
|
|
2012-04-22 10:29:18 +00:00
|
|
|
QHash<Uuid, Entry*>::const_iterator iEntry;
|
|
|
|
|
for (iEntry = m_entries.constBegin(); iEntry != m_entries.constEnd(); ++iEntry) {
|
|
|
|
|
iEntry.value()->setUpdateTimeinfo(true);
|
|
|
|
|
|
|
|
|
|
Q_FOREACH (Entry* histEntry, iEntry.value()->historyItems()) {
|
2012-04-17 00:26:25 +00:00
|
|
|
histEntry->setUpdateTimeinfo(true);
|
|
|
|
|
}
|
2012-04-11 17:51:54 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-13 16:08:06 +00:00
|
|
|
delete m_tmpParent;
|
2010-09-25 10:41:00 +00:00
|
|
|
}
|
2010-08-13 16:08:06 +00:00
|
|
|
|
2010-09-25 10:41:00 +00:00
|
|
|
Database* KeePass2XmlReader::readDatabase(QIODevice* device)
|
|
|
|
|
{
|
|
|
|
|
Database* db = new Database();
|
|
|
|
|
readDatabase(device, db);
|
|
|
|
|
return db;
|
2010-08-31 14:18:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Database* KeePass2XmlReader::readDatabase(const QString& filename)
|
|
|
|
|
{
|
|
|
|
|
QFile file(filename);
|
2010-09-13 21:24:36 +00:00
|
|
|
file.open(QIODevice::ReadOnly);
|
2010-08-31 14:18:45 +00:00
|
|
|
return readDatabase(&file);
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-06 19:03:13 +00:00
|
|
|
bool KeePass2XmlReader::hasError()
|
2010-08-31 14:18:45 +00:00
|
|
|
{
|
2013-06-30 12:43:02 +00:00
|
|
|
return m_error || m_xml.hasError();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 14:18:45 +00:00
|
|
|
QString KeePass2XmlReader::errorString()
|
2010-08-13 16:08:06 +00:00
|
|
|
{
|
2013-06-30 12:43:02 +00:00
|
|
|
if (m_error) {
|
|
|
|
|
return m_errorStr;
|
|
|
|
|
}
|
|
|
|
|
else if (m_xml.hasError()) {
|
|
|
|
|
return QString("XML error:\n%1\nLine %2, column %3")
|
|
|
|
|
.arg(m_xml.errorString())
|
|
|
|
|
.arg(m_xml.lineNumber())
|
|
|
|
|
.arg(m_xml.columnNumber());
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KeePass2XmlReader::raiseError(const QString& errorMessage)
|
|
|
|
|
{
|
|
|
|
|
m_error = true;
|
|
|
|
|
m_errorStr = errorMessage;
|
2010-08-13 16:08:06 +00:00
|
|
|
}
|
|
|
|
|
|
2012-09-25 20:33:36 +00:00
|
|
|
QByteArray KeePass2XmlReader::headerHash()
|
|
|
|
|
{
|
|
|
|
|
return m_headerHash;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-20 17:01:43 +00:00
|
|
|
bool KeePass2XmlReader::parseKeePassFile()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "KeePassFile");
|
|
|
|
|
|
2013-04-20 17:17:09 +00:00
|
|
|
bool rootElementFound = false;
|
|
|
|
|
bool rootParsedSuccesfully = false;
|
2013-04-20 17:01:43 +00:00
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "Meta") {
|
|
|
|
|
parseMeta();
|
|
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Root") {
|
2013-04-20 17:17:09 +00:00
|
|
|
if (rootElementFound) {
|
|
|
|
|
rootParsedSuccesfully = false;
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Multiple root elements");
|
2013-04-20 17:17:09 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-04-30 15:00:00 +00:00
|
|
|
rootParsedSuccesfully = parseRoot();
|
2013-04-20 17:17:09 +00:00
|
|
|
rootElementFound = true;
|
|
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-04-20 17:01:43 +00:00
|
|
|
|
2013-04-20 17:17:09 +00:00
|
|
|
return rootParsedSuccesfully;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
void KeePass2XmlReader::parseMeta()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Meta");
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "Generator") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setGenerator(readString());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
2012-09-25 20:33:36 +00:00
|
|
|
else if (m_xml.name() == "HeaderHash") {
|
|
|
|
|
m_headerHash = readBinary();
|
|
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
else if (m_xml.name() == "DatabaseName") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setName(readString());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "DatabaseNameChanged") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setNameChanged(readDateTime());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "DatabaseDescription") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setDescription(readString());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "DatabaseDescriptionChanged") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setDescriptionChanged(readDateTime());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "DefaultUserName") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setDefaultUserName(readString());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "DefaultUserNameChanged") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setDefaultUserNameChanged(readDateTime());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "MaintenanceHistoryDays") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setMaintenanceHistoryDays(readNumber());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
2012-04-21 14:45:46 +00:00
|
|
|
else if (m_xml.name() == "Color") {
|
|
|
|
|
m_meta->setColor(readColor());
|
|
|
|
|
}
|
2010-09-25 10:41:00 +00:00
|
|
|
else if (m_xml.name() == "MasterKeyChanged") {
|
|
|
|
|
m_meta->setMasterKeyChanged(readDateTime());
|
|
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "MasterKeyChangeRec") {
|
|
|
|
|
m_meta->setMasterKeyChangeRec(readNumber());
|
|
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "MasterKeyChangeForce") {
|
|
|
|
|
m_meta->setMasterKeyChangeForce(readNumber());
|
|
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
else if (m_xml.name() == "MemoryProtection") {
|
|
|
|
|
parseMemoryProtection();
|
|
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "CustomIcons") {
|
|
|
|
|
parseCustomIcons();
|
|
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "RecycleBinEnabled") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setRecycleBinEnabled(readBool());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "RecycleBinUUID") {
|
2010-08-13 16:08:06 +00:00
|
|
|
m_meta->setRecycleBin(getGroup(readUuid()));
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "RecycleBinChanged") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setRecycleBinChanged(readDateTime());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "EntryTemplatesGroup") {
|
2010-08-13 16:08:06 +00:00
|
|
|
m_meta->setEntryTemplatesGroup(getGroup(readUuid()));
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "EntryTemplatesGroupChanged") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setEntryTemplatesGroupChanged(readDateTime());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "LastSelectedGroup") {
|
2010-08-13 16:08:06 +00:00
|
|
|
m_meta->setLastSelectedGroup(getGroup(readUuid()));
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "LastTopVisibleGroup") {
|
2010-08-13 16:08:06 +00:00
|
|
|
m_meta->setLastTopVisibleGroup(getGroup(readUuid()));
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
2012-04-21 14:45:46 +00:00
|
|
|
else if (m_xml.name() == "HistoryMaxItems") {
|
2012-05-19 13:05:07 +00:00
|
|
|
int value = readNumber();
|
|
|
|
|
if (value >= -1) {
|
|
|
|
|
m_meta->setHistoryMaxItems(value);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("HistoryMaxItems invalid number");
|
2012-05-19 13:05:07 +00:00
|
|
|
}
|
2012-04-21 14:45:46 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "HistoryMaxSize") {
|
2012-05-19 13:05:07 +00:00
|
|
|
int value = readNumber();
|
|
|
|
|
if (value >= -1) {
|
|
|
|
|
m_meta->setHistoryMaxSize(value);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("HistoryMaxSize invalid number");
|
2012-05-19 13:05:07 +00:00
|
|
|
}
|
2012-04-21 14:45:46 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Binaries") {
|
|
|
|
|
parseBinaries();
|
|
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
else if (m_xml.name() == "CustomData") {
|
|
|
|
|
parseCustomData();
|
|
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
void KeePass2XmlReader::parseMemoryProtection()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "MemoryProtection");
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "ProtectTitle") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setProtectTitle(readBool());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "ProtectUserName") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setProtectUsername(readBool());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "ProtectPassword") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setProtectPassword(readBool());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "ProtectURL") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setProtectUrl(readBool());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "ProtectNotes") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setProtectNotes(readBool());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
2012-04-21 14:45:46 +00:00
|
|
|
/*else if (m_xml.name() == "AutoEnableVisualHiding") {
|
2010-08-12 19:38:59 +00:00
|
|
|
m_meta->setAutoEnableVisualHiding(readBool());
|
2012-04-21 14:45:46 +00:00
|
|
|
}*/
|
2010-08-07 13:10:44 +00:00
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
void KeePass2XmlReader::parseCustomIcons()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomIcons");
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "Icon") {
|
|
|
|
|
parseIcon();
|
|
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
void KeePass2XmlReader::parseIcon()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Icon");
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
Uuid uuid;
|
2013-04-14 13:06:34 +00:00
|
|
|
QImage icon;
|
|
|
|
|
bool uuidSet = false;
|
|
|
|
|
bool iconSet = false;
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "UUID") {
|
2010-08-12 19:38:59 +00:00
|
|
|
uuid = readUuid();
|
2013-04-14 13:06:34 +00:00
|
|
|
uuidSet = true;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Data") {
|
2012-01-01 20:52:54 +00:00
|
|
|
icon.loadFromData(readBinary());
|
2013-04-14 13:06:34 +00:00
|
|
|
iconSet = true;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-04-14 13:06:34 +00:00
|
|
|
|
|
|
|
|
if (uuidSet && iconSet) {
|
|
|
|
|
m_meta->addCustomIcon(uuid, icon);
|
|
|
|
|
}
|
2013-04-20 16:30:24 +00:00
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Missing icon uuid or data");
|
2013-04-20 16:30:24 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2012-04-21 14:45:46 +00:00
|
|
|
void KeePass2XmlReader::parseBinaries()
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Binaries");
|
|
|
|
|
|
|
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
|
|
|
|
if (m_xml.name() == "Binary") {
|
|
|
|
|
QXmlStreamAttributes attr = m_xml.attributes();
|
|
|
|
|
|
|
|
|
|
QString id = attr.value("ID").toString();
|
|
|
|
|
|
|
|
|
|
QByteArray data;
|
|
|
|
|
if (attr.value("Compressed").compare("True", Qt::CaseInsensitive) == 0) {
|
|
|
|
|
data = readCompressedBinary();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
data = readBinary();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_binaryPool.contains(id)) {
|
|
|
|
|
qWarning("KeePass2XmlReader::parseBinaries: overwriting binary item \"%s\"",
|
|
|
|
|
qPrintable(id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_binaryPool.insert(id, data);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
skipCurrentElement();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
void KeePass2XmlReader::parseCustomData()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomData");
|
|
|
|
|
|
2010-08-13 16:08:06 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-25 22:31:07 +00:00
|
|
|
if (m_xml.name() == "Item") {
|
|
|
|
|
parseCustomDataItem();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
skipCurrentElement();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
void KeePass2XmlReader::parseCustomDataItem()
|
2010-08-25 22:31:07 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Item");
|
|
|
|
|
|
|
|
|
|
QString key;
|
2013-04-14 13:06:34 +00:00
|
|
|
QString value;
|
|
|
|
|
bool keySet = false;
|
|
|
|
|
bool valueSet = false;
|
|
|
|
|
|
2010-08-25 22:31:07 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
|
|
|
|
if (m_xml.name() == "Key") {
|
|
|
|
|
key = readString();
|
2013-04-14 13:06:34 +00:00
|
|
|
keySet = true;
|
2010-08-25 22:31:07 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Value") {
|
2013-04-14 13:06:34 +00:00
|
|
|
value = readString();
|
|
|
|
|
valueSet = true;
|
2010-08-25 22:31:07 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
skipCurrentElement();
|
|
|
|
|
}
|
2010-08-13 16:08:06 +00:00
|
|
|
}
|
2013-04-14 13:06:34 +00:00
|
|
|
|
|
|
|
|
if (keySet && valueSet) {
|
|
|
|
|
m_meta->addCustomField(key, value);
|
|
|
|
|
}
|
2013-04-20 16:30:24 +00:00
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Missing custom data key or value");
|
2013-04-20 16:30:24 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-20 17:01:43 +00:00
|
|
|
bool KeePass2XmlReader::parseRoot()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Root");
|
|
|
|
|
|
2013-04-20 17:17:09 +00:00
|
|
|
bool groupElementFound = false;
|
|
|
|
|
bool groupParsedSuccesfully = false;
|
2013-04-20 17:01:43 +00:00
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "Group") {
|
2013-04-30 15:00:00 +00:00
|
|
|
if (groupElementFound) {
|
|
|
|
|
groupParsedSuccesfully = false;
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Multiple group elements");
|
2013-04-30 15:00:00 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
Group* rootGroup = parseGroup();
|
2010-08-12 19:43:57 +00:00
|
|
|
if (rootGroup) {
|
2011-07-09 19:54:01 +00:00
|
|
|
Group* oldRoot = m_db->rootGroup();
|
2011-07-08 11:57:02 +00:00
|
|
|
m_db->setRootGroup(rootGroup);
|
2011-07-09 19:54:01 +00:00
|
|
|
delete oldRoot;
|
2013-04-20 17:17:09 +00:00
|
|
|
groupParsedSuccesfully = true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-30 15:00:00 +00:00
|
|
|
groupElementFound = true;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "DeletedObjects") {
|
2010-08-25 11:52:59 +00:00
|
|
|
parseDeletedObjects();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-04-20 17:01:43 +00:00
|
|
|
|
2013-04-20 17:17:09 +00:00
|
|
|
return groupParsedSuccesfully;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
Group* KeePass2XmlReader::parseGroup()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Group");
|
|
|
|
|
|
2013-04-14 12:54:56 +00:00
|
|
|
Group* group = new Group();
|
|
|
|
|
group->setUpdateTimeinfo(false);
|
|
|
|
|
QList<Group*> children;
|
|
|
|
|
QList<Entry*> entries;
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "UUID") {
|
2010-08-12 19:38:59 +00:00
|
|
|
Uuid uuid = readUuid();
|
|
|
|
|
if (uuid.isNull()) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Null group uuid");
|
2010-08-12 19:38:59 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-04-14 12:54:56 +00:00
|
|
|
group->setUuid(uuid);
|
2011-07-09 19:54:01 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Name") {
|
2010-08-12 19:38:59 +00:00
|
|
|
group->setName(readString());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Notes") {
|
2010-08-12 19:38:59 +00:00
|
|
|
group->setNotes(readString());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "IconID") {
|
2010-08-12 19:38:59 +00:00
|
|
|
int iconId = readNumber();
|
2010-08-14 10:24:35 +00:00
|
|
|
if (iconId < 0) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Invalid group icon number");
|
2010-08-14 10:24:35 +00:00
|
|
|
}
|
2010-08-25 17:26:01 +00:00
|
|
|
else {
|
2012-06-29 13:22:43 +00:00
|
|
|
if (iconId >= DatabaseIcons::IconCount) {
|
2010-09-22 22:21:36 +00:00
|
|
|
qWarning("KeePass2XmlReader::parseGroup: icon id \"%d\" not supported", iconId);
|
|
|
|
|
}
|
2010-08-12 19:38:59 +00:00
|
|
|
group->setIcon(iconId);
|
2010-08-14 10:24:35 +00:00
|
|
|
}
|
2010-08-12 19:38:59 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "CustomIconUUID") {
|
|
|
|
|
Uuid uuid = readUuid();
|
|
|
|
|
if (!uuid.isNull()) {
|
|
|
|
|
group->setIcon(uuid);
|
|
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Times") {
|
2010-08-12 19:38:59 +00:00
|
|
|
group->setTimeInfo(parseTimes());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "IsExpanded") {
|
2010-08-12 19:38:59 +00:00
|
|
|
group->setExpanded(readBool());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "DefaultAutoTypeSequence") {
|
2010-08-12 19:38:59 +00:00
|
|
|
group->setDefaultAutoTypeSequence(readString());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "EnableAutoType") {
|
2010-08-19 12:03:54 +00:00
|
|
|
QString str = readString();
|
|
|
|
|
|
|
|
|
|
if (str.compare("null", Qt::CaseInsensitive) == 0) {
|
2011-07-07 10:45:14 +00:00
|
|
|
group->setAutoTypeEnabled(Group::Inherit);
|
2010-08-19 12:03:54 +00:00
|
|
|
}
|
|
|
|
|
else if (str.compare("true", Qt::CaseInsensitive) == 0) {
|
2011-07-07 10:45:14 +00:00
|
|
|
group->setAutoTypeEnabled(Group::Enable);
|
2010-08-19 12:03:54 +00:00
|
|
|
}
|
|
|
|
|
else if (str.compare("false", Qt::CaseInsensitive) == 0) {
|
2011-07-07 10:45:14 +00:00
|
|
|
group->setAutoTypeEnabled(Group::Disable);
|
2010-08-19 12:03:54 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Invalid EnableAutoType value");
|
2010-08-19 12:03:54 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "EnableSearching") {
|
2010-08-19 12:03:54 +00:00
|
|
|
QString str = readString();
|
|
|
|
|
|
|
|
|
|
if (str.compare("null", Qt::CaseInsensitive) == 0) {
|
2011-07-07 10:45:14 +00:00
|
|
|
group->setSearchingEnabled(Group::Inherit);
|
2010-08-19 12:03:54 +00:00
|
|
|
}
|
|
|
|
|
else if (str.compare("true", Qt::CaseInsensitive) == 0) {
|
2011-07-07 10:45:14 +00:00
|
|
|
group->setSearchingEnabled(Group::Enable);
|
2010-08-19 12:03:54 +00:00
|
|
|
}
|
|
|
|
|
else if (str.compare("false", Qt::CaseInsensitive) == 0) {
|
2011-07-07 10:45:14 +00:00
|
|
|
group->setSearchingEnabled(Group::Disable);
|
2010-08-19 12:03:54 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Invalid EnableSearching value");
|
2010-08-19 12:03:54 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "LastTopVisibleEntry") {
|
2010-08-13 16:08:06 +00:00
|
|
|
group->setLastTopVisibleEntry(getEntry(readUuid()));
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Group") {
|
2010-08-12 19:38:59 +00:00
|
|
|
Group* newGroup = parseGroup();
|
|
|
|
|
if (newGroup) {
|
2013-04-14 12:54:56 +00:00
|
|
|
children.append(newGroup);
|
2010-08-12 19:38:59 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Entry") {
|
2010-08-25 11:52:59 +00:00
|
|
|
Entry* newEntry = parseEntry(false);
|
2010-08-12 19:38:59 +00:00
|
|
|
if (newEntry) {
|
2013-04-14 12:54:56 +00:00
|
|
|
entries.append(newEntry);
|
2010-08-12 19:38:59 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-08-12 19:38:59 +00:00
|
|
|
|
2013-04-20 16:30:24 +00:00
|
|
|
if (!group->uuid().isNull()) {
|
|
|
|
|
Group* tmpGroup = group;
|
|
|
|
|
group = getGroup(tmpGroup->uuid());
|
|
|
|
|
group->copyDataFrom(tmpGroup);
|
|
|
|
|
group->setUpdateTimeinfo(false);
|
|
|
|
|
delete tmpGroup;
|
|
|
|
|
}
|
2013-06-30 12:43:02 +00:00
|
|
|
else if (!hasError()) {
|
|
|
|
|
raiseError("No group uuid found");
|
2013-04-20 16:30:24 +00:00
|
|
|
}
|
2013-04-14 12:54:56 +00:00
|
|
|
|
|
|
|
|
Q_FOREACH (Group* child, children) {
|
|
|
|
|
child->setParent(group);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Q_FOREACH (Entry* entry, entries) {
|
|
|
|
|
entry->setGroup(group);
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
return group;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
void KeePass2XmlReader::parseDeletedObjects()
|
2010-08-25 11:52:59 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "DeletedObjects");
|
|
|
|
|
|
|
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
|
|
|
|
if (m_xml.name() == "DeletedObject") {
|
|
|
|
|
parseDeletedObject();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
skipCurrentElement();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
void KeePass2XmlReader::parseDeletedObject()
|
2010-08-25 11:52:59 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "DeletedObject");
|
|
|
|
|
|
|
|
|
|
DeletedObject delObj;
|
|
|
|
|
|
|
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
|
|
|
|
if (m_xml.name() == "UUID") {
|
|
|
|
|
Uuid uuid = readUuid();
|
|
|
|
|
if (uuid.isNull()) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Null DeleteObject uuid");
|
2010-08-25 11:52:59 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
delObj.uuid = uuid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "DeletionTime") {
|
|
|
|
|
delObj.deletionTime = readDateTime();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
skipCurrentElement();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-20 16:30:24 +00:00
|
|
|
if (!delObj.uuid.isNull() && !delObj.deletionTime.isNull()) {
|
|
|
|
|
m_db->addDeletedObject(delObj);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Missing DeletedObject uuid or time");
|
2013-04-20 16:30:24 +00:00
|
|
|
}
|
2010-08-25 11:52:59 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
Entry* KeePass2XmlReader::parseEntry(bool history)
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Entry");
|
|
|
|
|
|
2013-04-14 12:31:19 +00:00
|
|
|
Entry* entry = new Entry();
|
|
|
|
|
entry->setUpdateTimeinfo(false);
|
|
|
|
|
QList<Entry*> historyItems;
|
|
|
|
|
QList<StringPair> binaryRefs;
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "UUID") {
|
2010-08-12 19:38:59 +00:00
|
|
|
Uuid uuid = readUuid();
|
|
|
|
|
if (uuid.isNull()) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Null entry uuid");
|
2010-08-12 19:38:59 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-04-14 12:31:19 +00:00
|
|
|
entry->setUuid(uuid);
|
2010-08-25 11:52:59 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "IconID") {
|
2010-08-12 19:38:59 +00:00
|
|
|
int iconId = readNumber();
|
2010-08-14 10:24:35 +00:00
|
|
|
if (iconId < 0) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Invalud entry icon number");
|
2010-08-14 10:24:35 +00:00
|
|
|
}
|
2010-08-25 17:26:01 +00:00
|
|
|
else {
|
2010-08-12 19:38:59 +00:00
|
|
|
entry->setIcon(iconId);
|
2010-08-14 10:24:35 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "CustomIconUUID") {
|
2010-08-12 19:38:59 +00:00
|
|
|
Uuid uuid = readUuid();
|
2010-09-19 19:22:24 +00:00
|
|
|
if (!uuid.isNull()) {
|
2010-08-12 19:38:59 +00:00
|
|
|
entry->setIcon(uuid);
|
2010-09-19 19:22:24 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "ForegroundColor") {
|
2010-08-12 19:38:59 +00:00
|
|
|
entry->setForegroundColor(readColor());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "BackgroundColor") {
|
2010-08-12 19:38:59 +00:00
|
|
|
entry->setBackgroundColor(readColor());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "OverrideURL") {
|
2010-08-12 19:38:59 +00:00
|
|
|
entry->setOverrideUrl(readString());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
2010-09-25 10:41:00 +00:00
|
|
|
else if (m_xml.name() == "Tags") {
|
|
|
|
|
entry->setTags(readString());
|
|
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
else if (m_xml.name() == "Times") {
|
2010-08-12 19:38:59 +00:00
|
|
|
entry->setTimeInfo(parseTimes());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "String") {
|
2010-08-12 19:38:59 +00:00
|
|
|
parseEntryString(entry);
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Binary") {
|
2013-04-14 12:31:19 +00:00
|
|
|
QPair<QString, QString> ref = parseEntryBinary(entry);
|
|
|
|
|
if (!ref.first.isNull() && !ref.second.isNull()) {
|
|
|
|
|
binaryRefs.append(ref);
|
|
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "AutoType") {
|
2010-08-12 19:38:59 +00:00
|
|
|
parseAutoType(entry);
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "History") {
|
2010-08-25 11:52:59 +00:00
|
|
|
if (history) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("History element in history entry");
|
2010-08-25 11:52:59 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-04-14 12:31:19 +00:00
|
|
|
historyItems = parseEntryHistory();
|
2010-08-25 11:52:59 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-08-13 16:08:06 +00:00
|
|
|
|
2013-06-30 12:43:02 +00:00
|
|
|
if (!entry->uuid().isNull()) {
|
|
|
|
|
if (history) {
|
|
|
|
|
entry->setUpdateTimeinfo(false);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Entry* tmpEntry = entry;
|
2013-04-14 12:31:19 +00:00
|
|
|
|
2013-06-30 12:43:02 +00:00
|
|
|
entry = getEntry(tmpEntry->uuid());
|
|
|
|
|
entry->copyDataFrom(tmpEntry);
|
|
|
|
|
entry->setUpdateTimeinfo(false);
|
2013-04-14 12:31:19 +00:00
|
|
|
|
2013-06-30 12:43:02 +00:00
|
|
|
delete tmpEntry;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!hasError()) {
|
|
|
|
|
raiseError("No entry uuid found");
|
2013-04-14 12:31:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Q_FOREACH (Entry* historyItem, historyItems) {
|
|
|
|
|
entry->addHistoryItem(historyItem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Q_FOREACH (const StringPair& ref, binaryRefs) {
|
|
|
|
|
m_binaryMap.insertMulti(ref.first, qMakePair(entry, ref.second));
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 16:08:06 +00:00
|
|
|
return entry;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:04:03 +00:00
|
|
|
void KeePass2XmlReader::parseEntryString(Entry* entry)
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "String");
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
QString key;
|
2013-04-14 13:06:34 +00:00
|
|
|
QString value;
|
2013-05-01 10:03:03 +00:00
|
|
|
bool protect = false;
|
2013-04-14 13:06:34 +00:00
|
|
|
bool keySet = false;
|
|
|
|
|
bool valueSet = false;
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "Key") {
|
2010-08-12 19:38:59 +00:00
|
|
|
key = readString();
|
2013-04-14 13:06:34 +00:00
|
|
|
keySet = true;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Value") {
|
2011-01-13 21:31:17 +00:00
|
|
|
QXmlStreamAttributes attr = m_xml.attributes();
|
2013-04-14 13:06:34 +00:00
|
|
|
value = readString();
|
2011-01-13 21:31:17 +00:00
|
|
|
|
2012-04-21 14:45:46 +00:00
|
|
|
bool isProtected = attr.value("Protected") == "True";
|
|
|
|
|
bool protectInMemory = attr.value("ProtectInMemory") == "True";
|
2011-01-13 21:31:17 +00:00
|
|
|
|
|
|
|
|
if (isProtected && !value.isEmpty()) {
|
2011-07-06 22:15:52 +00:00
|
|
|
if (m_randomStream) {
|
2012-06-24 16:22:18 +00:00
|
|
|
value = QString::fromUtf8(m_randomStream->process(QByteArray::fromBase64(value.toAscii())));
|
2011-01-13 21:31:17 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Unable to decrypt entry string");
|
2011-01-13 21:31:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-14 13:06:34 +00:00
|
|
|
protect = isProtected || protectInMemory;
|
|
|
|
|
valueSet = true;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-04-14 13:06:34 +00:00
|
|
|
|
|
|
|
|
if (keySet && valueSet) {
|
|
|
|
|
entry->attributes()->set(key, value, protect);
|
|
|
|
|
}
|
2013-04-20 16:30:24 +00:00
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Entry string key or value missing");
|
2013-04-20 16:30:24 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-14 12:31:19 +00:00
|
|
|
QPair<QString, QString> KeePass2XmlReader::parseEntryBinary(Entry* entry)
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Binary");
|
|
|
|
|
|
2013-04-14 12:31:19 +00:00
|
|
|
QPair<QString, QString> poolRef;
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
QString key;
|
2013-04-14 13:06:34 +00:00
|
|
|
QByteArray value;
|
|
|
|
|
bool keySet = false;
|
|
|
|
|
bool valueSet = false;
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "Key") {
|
2010-08-12 19:38:59 +00:00
|
|
|
key = readString();
|
2013-04-14 13:06:34 +00:00
|
|
|
keySet = true;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Value") {
|
2011-01-13 21:31:17 +00:00
|
|
|
QXmlStreamAttributes attr = m_xml.attributes();
|
|
|
|
|
|
2012-04-21 14:45:46 +00:00
|
|
|
if (attr.hasAttribute("Ref")) {
|
2013-04-14 12:31:19 +00:00
|
|
|
poolRef = qMakePair(attr.value("Ref").toString(), key);
|
2012-04-21 14:45:46 +00:00
|
|
|
m_xml.skipCurrentElement();
|
2011-01-13 21:31:17 +00:00
|
|
|
}
|
2012-04-21 14:45:46 +00:00
|
|
|
else {
|
|
|
|
|
// format compatbility
|
2013-04-14 13:06:34 +00:00
|
|
|
value = readBinary();
|
2012-04-21 14:45:46 +00:00
|
|
|
bool isProtected = attr.hasAttribute("Protected")
|
|
|
|
|
&& (attr.value("Protected") == "True");
|
|
|
|
|
|
|
|
|
|
if (isProtected && !value.isEmpty()) {
|
|
|
|
|
m_randomStream->processInPlace(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-20 16:30:24 +00:00
|
|
|
|
|
|
|
|
valueSet = true;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-04-14 12:31:19 +00:00
|
|
|
|
2013-04-14 13:06:34 +00:00
|
|
|
if (keySet && valueSet) {
|
|
|
|
|
entry->attachments()->set(key, value);
|
|
|
|
|
}
|
2013-04-20 16:30:24 +00:00
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Entry binary key or value missing");
|
2013-04-20 16:30:24 +00:00
|
|
|
}
|
2013-04-14 13:06:34 +00:00
|
|
|
|
2013-04-14 12:31:19 +00:00
|
|
|
return poolRef;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
void KeePass2XmlReader::parseAutoType(Entry* entry)
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "AutoType");
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "Enabled") {
|
2010-08-12 19:38:59 +00:00
|
|
|
entry->setAutoTypeEnabled(readBool());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "DataTransferObfuscation") {
|
2010-08-12 19:38:59 +00:00
|
|
|
entry->setAutoTypeObfuscation(readNumber());
|
|
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "DefaultSequence") {
|
|
|
|
|
entry->setDefaultAutoTypeSequence(readString());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Association") {
|
2010-08-12 19:38:59 +00:00
|
|
|
parseAutoTypeAssoc(entry);
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:04:03 +00:00
|
|
|
void KeePass2XmlReader::parseAutoTypeAssoc(Entry* entry)
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Association");
|
|
|
|
|
|
2012-07-16 07:54:04 +00:00
|
|
|
AutoTypeAssociations::Association assoc;
|
2013-04-14 13:06:34 +00:00
|
|
|
bool windowSet = false;
|
|
|
|
|
bool sequenceSet = false;
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "Window") {
|
2010-08-12 19:38:59 +00:00
|
|
|
assoc.window = readString();
|
2013-04-14 13:06:34 +00:00
|
|
|
windowSet = true;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "KeystrokeSequence") {
|
2010-08-12 19:38:59 +00:00
|
|
|
assoc.sequence = readString();
|
2013-04-14 13:06:34 +00:00
|
|
|
sequenceSet = true;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-04-14 13:06:34 +00:00
|
|
|
|
|
|
|
|
if (windowSet && sequenceSet) {
|
|
|
|
|
entry->autoTypeAssociations()->add(assoc);
|
|
|
|
|
}
|
2013-04-20 16:30:24 +00:00
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Auto-type association window or sequence missing");
|
2013-04-20 16:30:24 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-14 12:31:19 +00:00
|
|
|
QList<Entry*> KeePass2XmlReader::parseEntryHistory()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "History");
|
|
|
|
|
|
2013-04-14 12:31:19 +00:00
|
|
|
QList<Entry*> historyItems;
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "Entry") {
|
2013-04-14 12:31:19 +00:00
|
|
|
historyItems.append(parseEntry(true));
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-04-14 12:31:19 +00:00
|
|
|
|
|
|
|
|
return historyItems;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
TimeInfo KeePass2XmlReader::parseTimes()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Times");
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
TimeInfo timeInfo;
|
|
|
|
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
2010-08-07 13:10:44 +00:00
|
|
|
if (m_xml.name() == "LastModificationTime") {
|
2010-08-12 19:38:59 +00:00
|
|
|
timeInfo.setLastModificationTime(readDateTime());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "CreationTime") {
|
2010-08-12 19:38:59 +00:00
|
|
|
timeInfo.setCreationTime(readDateTime());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "LastAccessTime") {
|
2010-08-12 19:38:59 +00:00
|
|
|
timeInfo.setLastAccessTime(readDateTime());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "ExpiryTime") {
|
2010-08-12 19:38:59 +00:00
|
|
|
timeInfo.setExpiryTime(readDateTime());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "Expires") {
|
2010-08-12 19:38:59 +00:00
|
|
|
timeInfo.setExpires(readBool());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "UsageCount") {
|
2010-08-12 19:38:59 +00:00
|
|
|
timeInfo.setUsageCount(readNumber());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else if (m_xml.name() == "LocationChanged") {
|
2010-08-12 19:38:59 +00:00
|
|
|
timeInfo.setLocationChanged(readDateTime());
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
skipCurrentElement();
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-08-12 19:38:59 +00:00
|
|
|
|
|
|
|
|
return timeInfo;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
QString KeePass2XmlReader::readString()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
return m_xml.readElementText();
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
bool KeePass2XmlReader::readBool()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
QString str = readString();
|
|
|
|
|
|
2010-08-19 12:03:54 +00:00
|
|
|
if (str.compare("True", Qt::CaseInsensitive) == 0) {
|
2010-08-07 13:10:44 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2010-08-19 12:03:54 +00:00
|
|
|
else if (str.compare("False", Qt::CaseInsensitive) == 0) {
|
2010-08-07 13:10:44 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Invalid bool value");
|
2010-08-13 16:08:06 +00:00
|
|
|
return false;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
QDateTime KeePass2XmlReader::readDateTime()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
|
|
|
|
QString str = readString();
|
|
|
|
|
QDateTime dt = QDateTime::fromString(str, Qt::ISODate);
|
|
|
|
|
|
|
|
|
|
if (!dt.isValid()) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Invalid date time value");
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dt;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
QColor KeePass2XmlReader::readColor()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
2010-08-12 19:38:59 +00:00
|
|
|
QString colorStr = readString();
|
2010-08-13 16:08:06 +00:00
|
|
|
|
|
|
|
|
if (colorStr.isEmpty()) {
|
|
|
|
|
return QColor();
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-12 19:38:59 +00:00
|
|
|
if (colorStr.length() != 7 || colorStr[0] != '#') {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Invalid color value");
|
2010-08-12 19:38:59 +00:00
|
|
|
return QColor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QColor color;
|
2012-04-18 20:08:22 +00:00
|
|
|
for (int i = 0; i <= 2; i++) {
|
2010-08-12 19:38:59 +00:00
|
|
|
QString rgbPartStr = colorStr.mid(1 + 2*i, 2);
|
|
|
|
|
bool ok;
|
2010-08-13 16:08:06 +00:00
|
|
|
int rgbPart = rgbPartStr.toInt(&ok, 16);
|
2010-08-12 19:38:59 +00:00
|
|
|
if (!ok || rgbPart > 255) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Invalid color rgb part");
|
2010-08-12 19:38:59 +00:00
|
|
|
return QColor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
color.setRed(rgbPart);
|
|
|
|
|
}
|
|
|
|
|
else if (i == 1) {
|
|
|
|
|
color.setGreen(rgbPart);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
color.setBlue(rgbPart);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return color;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
int KeePass2XmlReader::readNumber()
|
2010-08-12 19:38:59 +00:00
|
|
|
{
|
|
|
|
|
bool ok;
|
|
|
|
|
int result = readString().toInt(&ok);
|
|
|
|
|
if (!ok) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Invalid number value");
|
2010-08-12 19:38:59 +00:00
|
|
|
}
|
|
|
|
|
return result;
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
Uuid KeePass2XmlReader::readUuid()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
2010-08-12 19:38:59 +00:00
|
|
|
QByteArray uuidBin = readBinary();
|
2012-05-14 17:10:42 +00:00
|
|
|
if (uuidBin.length() != Uuid::Length) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Invalid uuid value");
|
2010-08-12 19:38:59 +00:00
|
|
|
return Uuid();
|
|
|
|
|
}
|
|
|
|
|
else {
|
2010-08-13 16:08:06 +00:00
|
|
|
return Uuid(uuidBin);
|
2010-08-12 19:38:59 +00:00
|
|
|
}
|
2010-08-07 13:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
QByteArray KeePass2XmlReader::readBinary()
|
2010-08-07 13:10:44 +00:00
|
|
|
{
|
2010-08-12 19:38:59 +00:00
|
|
|
return QByteArray::fromBase64(readString().toAscii());
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-21 14:45:46 +00:00
|
|
|
QByteArray KeePass2XmlReader::readCompressedBinary()
|
|
|
|
|
{
|
|
|
|
|
QByteArray rawData = readBinary();
|
|
|
|
|
|
|
|
|
|
QBuffer buffer(&rawData);
|
|
|
|
|
buffer.open(QIODevice::ReadOnly);
|
|
|
|
|
|
|
|
|
|
QtIOCompressor compressor(&buffer);
|
|
|
|
|
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
|
|
|
|
compressor.open(QIODevice::ReadOnly);
|
|
|
|
|
|
|
|
|
|
QByteArray result;
|
2012-05-02 09:06:24 +00:00
|
|
|
if (!Tools::readAllFromDevice(&compressor, result)) {
|
2013-06-30 12:43:02 +00:00
|
|
|
raiseError("Unable to decompress binary");
|
2012-04-21 14:45:46 +00:00
|
|
|
}
|
2012-05-02 09:06:24 +00:00
|
|
|
return result;
|
2012-04-21 14:45:46 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
Group* KeePass2XmlReader::getGroup(const Uuid& uuid)
|
2010-08-12 19:38:59 +00:00
|
|
|
{
|
2010-08-13 16:08:06 +00:00
|
|
|
if (uuid.isNull()) {
|
2012-07-23 12:58:57 +00:00
|
|
|
return Q_NULLPTR;
|
2010-08-13 16:08:06 +00:00
|
|
|
}
|
|
|
|
|
|
2012-04-22 10:29:18 +00:00
|
|
|
if (m_groups.contains(uuid)) {
|
|
|
|
|
return m_groups.value(uuid);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Group* group = new Group();
|
|
|
|
|
group->setUpdateTimeinfo(false);
|
|
|
|
|
group->setUuid(uuid);
|
|
|
|
|
group->setParent(m_tmpParent);
|
|
|
|
|
m_groups.insert(uuid, group);
|
|
|
|
|
return group;
|
2010-08-12 19:38:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
Entry* KeePass2XmlReader::getEntry(const Uuid& uuid)
|
2010-08-12 19:38:59 +00:00
|
|
|
{
|
2010-08-13 16:08:06 +00:00
|
|
|
if (uuid.isNull()) {
|
2012-07-23 12:58:57 +00:00
|
|
|
return Q_NULLPTR;
|
2010-08-13 16:08:06 +00:00
|
|
|
}
|
|
|
|
|
|
2012-04-22 10:29:18 +00:00
|
|
|
if (m_entries.contains(uuid)) {
|
|
|
|
|
return m_entries.value(uuid);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Entry* entry = new Entry();
|
|
|
|
|
entry->setUpdateTimeinfo(false);
|
|
|
|
|
entry->setUuid(uuid);
|
|
|
|
|
entry->setGroup(m_tmpParent);
|
|
|
|
|
m_entries.insert(uuid, entry);
|
|
|
|
|
return entry;
|
2010-08-12 19:38:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 12:39:35 +00:00
|
|
|
void KeePass2XmlReader::skipCurrentElement()
|
2010-08-13 16:08:06 +00:00
|
|
|
{
|
2010-09-22 22:21:36 +00:00
|
|
|
qWarning("KeePass2XmlReader::skipCurrentElement: skip element \"%s\"", qPrintable(m_xml.name().toString()));
|
2010-08-13 16:08:06 +00:00
|
|
|
m_xml.skipCurrentElement();
|
|
|
|
|
}
|