mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-12-16 00:44:17 -05:00
Move core/Parser to format/KeePass2XmlReader and core/Writer to format/KeePass2XmlWriter.
This commit is contained in:
parent
3bf0564436
commit
ee4c2c3dd4
9 changed files with 82 additions and 83 deletions
747
src/format/KeePass2XmlReader.cpp
Normal file
747
src/format/KeePass2XmlReader.cpp
Normal file
|
|
@ -0,0 +1,747 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "KeePass2XmlReader.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include "core/Database.h"
|
||||
#include "core/Metadata.h"
|
||||
|
||||
KeePass2XmlReader::KeePass2XmlReader(Database* db)
|
||||
{
|
||||
m_db = db;
|
||||
m_meta = db->metadata();
|
||||
}
|
||||
|
||||
bool KeePass2XmlReader::parse(const QString& filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||
m_xml.setDevice(&file);
|
||||
|
||||
m_tmpParent = new Group();
|
||||
m_tmpParent->setParent(m_db);
|
||||
|
||||
if (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||
if (m_xml.name() == "KeePassFile") {
|
||||
parseKeePassFile();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_xml.error() && !m_tmpParent->children().isEmpty()) {
|
||||
raiseError();
|
||||
}
|
||||
|
||||
delete m_tmpParent;
|
||||
|
||||
return !m_xml.error();
|
||||
}
|
||||
|
||||
QString KeePass2XmlReader::errorMsg()
|
||||
{
|
||||
return QString("%1\nLine %2, column %3")
|
||||
.arg(m_xml.errorString())
|
||||
.arg(m_xml.lineNumber())
|
||||
.arg(m_xml.columnNumber());
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseKeePassFile()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "KeePassFile");
|
||||
|
||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||
if (m_xml.name() == "Meta") {
|
||||
parseMeta();
|
||||
}
|
||||
else if (m_xml.name() == "Root") {
|
||||
parseRoot();
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseMeta()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Meta");
|
||||
|
||||
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();
|
||||
}
|
||||
else if (m_xml.name() == "CustomIcons") {
|
||||
parseCustomIcons();
|
||||
}
|
||||
else if (m_xml.name() == "RecycleBinEnabled") {
|
||||
m_meta->setRecycleBinEnabled(readBool());
|
||||
}
|
||||
else if (m_xml.name() == "RecycleBinUUID") {
|
||||
m_meta->setRecycleBin(getGroup(readUuid()));
|
||||
}
|
||||
else if (m_xml.name() == "RecycleBinChanged") {
|
||||
m_meta->setRecycleBinChanged(readDateTime());
|
||||
}
|
||||
else if (m_xml.name() == "EntryTemplatesGroup") {
|
||||
m_meta->setEntryTemplatesGroup(getGroup(readUuid()));
|
||||
}
|
||||
else if (m_xml.name() == "EntryTemplatesGroupChanged") {
|
||||
m_meta->setEntryTemplatesGroupChanged(readDateTime());
|
||||
}
|
||||
else if (m_xml.name() == "LastSelectedGroup") {
|
||||
m_meta->setLastSelectedGroup(getGroup(readUuid()));
|
||||
}
|
||||
else if (m_xml.name() == "LastTopVisibleGroup") {
|
||||
m_meta->setLastTopVisibleGroup(getGroup(readUuid()));
|
||||
}
|
||||
else if (m_xml.name() == "CustomData") {
|
||||
parseCustomData();
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseMemoryProtection()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "MemoryProtection");
|
||||
|
||||
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 {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseCustomIcons()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomIcons");
|
||||
|
||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||
if (m_xml.name() == "Icon") {
|
||||
parseIcon();
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseIcon()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Icon");
|
||||
|
||||
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 {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseCustomData()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomData");
|
||||
|
||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||
if (m_xml.name() == "Item") {
|
||||
parseCustomDataItem();
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseCustomDataItem()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Item");
|
||||
|
||||
QString key;
|
||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||
if (m_xml.name() == "Key") {
|
||||
key = readString();
|
||||
}
|
||||
else if (m_xml.name() == "Value") {
|
||||
m_meta->addCustomField(key, readString());
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseRoot()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Root");
|
||||
|
||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||
if (m_xml.name() == "Group") {
|
||||
Group* rootGroup = parseGroup();
|
||||
if (rootGroup) {
|
||||
rootGroup->setParent(m_db);
|
||||
}
|
||||
}
|
||||
else if (m_xml.name() == "DeletedObjects") {
|
||||
parseDeletedObjects();
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Group* KeePass2XmlReader::parseGroup()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Group");
|
||||
|
||||
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) {
|
||||
raiseError();
|
||||
}
|
||||
else {
|
||||
group->setIcon(iconId);
|
||||
}
|
||||
}
|
||||
else if (m_xml.name() == "CustomIconUUID") {
|
||||
Uuid uuid = readUuid();
|
||||
if (!uuid.isNull()) {
|
||||
group->setIcon(uuid);
|
||||
}
|
||||
}
|
||||
else if (m_xml.name() == "Times") {
|
||||
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") {
|
||||
QString str = readString();
|
||||
|
||||
if (str.compare("null", Qt::CaseInsensitive) == 0) {
|
||||
group->setAutoTypeEnabled(-1);
|
||||
}
|
||||
else if (str.compare("true", Qt::CaseInsensitive) == 0) {
|
||||
group->setAutoTypeEnabled(1);
|
||||
}
|
||||
else if (str.compare("false", Qt::CaseInsensitive) == 0) {
|
||||
group->setAutoTypeEnabled(0);
|
||||
}
|
||||
else {
|
||||
raiseError();
|
||||
}
|
||||
|
||||
}
|
||||
else if (m_xml.name() == "EnableSearching") {
|
||||
QString str = readString();
|
||||
|
||||
if (str.compare("null", Qt::CaseInsensitive) == 0) {
|
||||
group->setSearchingEnabled(-1);
|
||||
}
|
||||
else if (str.compare("true", Qt::CaseInsensitive) == 0) {
|
||||
group->setSearchingEnabled(1);
|
||||
}
|
||||
else if (str.compare("false", Qt::CaseInsensitive) == 0) {
|
||||
group->setSearchingEnabled(0);
|
||||
}
|
||||
else {
|
||||
raiseError();
|
||||
}
|
||||
}
|
||||
else if (m_xml.name() == "LastTopVisibleEntry") {
|
||||
group->setLastTopVisibleEntry(getEntry(readUuid()));
|
||||
}
|
||||
else if (m_xml.name() == "Group") {
|
||||
Group* newGroup = parseGroup();
|
||||
if (newGroup) {
|
||||
newGroup->setParent(group);
|
||||
}
|
||||
}
|
||||
else if (m_xml.name() == "Entry") {
|
||||
Entry* newEntry = parseEntry(false);
|
||||
if (newEntry) {
|
||||
newEntry->setGroup(group);
|
||||
}
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseDeletedObjects()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "DeletedObjects");
|
||||
|
||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||
if (m_xml.name() == "DeletedObject") {
|
||||
parseDeletedObject();
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseDeletedObject()
|
||||
{
|
||||
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()) {
|
||||
raiseError();
|
||||
}
|
||||
else {
|
||||
delObj.uuid = uuid;
|
||||
}
|
||||
}
|
||||
else if (m_xml.name() == "DeletionTime") {
|
||||
delObj.deletionTime = readDateTime();
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
m_db->addDeletedObject(delObj);
|
||||
}
|
||||
|
||||
Entry* KeePass2XmlReader::parseEntry(bool history)
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Entry");
|
||||
|
||||
Entry* entry = 0;
|
||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||
if (m_xml.name() == "UUID") {
|
||||
Uuid uuid = readUuid();
|
||||
if (uuid.isNull()) {
|
||||
raiseError();
|
||||
}
|
||||
else {
|
||||
if (history) {
|
||||
entry = new Entry();
|
||||
entry->setUuid(uuid);
|
||||
}
|
||||
else {
|
||||
entry = getEntry(uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_xml.name() == "IconID") {
|
||||
int iconId = readNumber();
|
||||
if (iconId < 0) {
|
||||
raiseError();
|
||||
}
|
||||
else {
|
||||
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") {
|
||||
entry->setTimeInfo(parseTimes());
|
||||
}
|
||||
else if (m_xml.name() == "String") {
|
||||
parseEntryString(entry);
|
||||
}
|
||||
else if (m_xml.name() == "Binary") {
|
||||
parseEntryBinary(entry);
|
||||
}
|
||||
else if (m_xml.name() == "AutoType") {
|
||||
parseAutoType(entry);
|
||||
}
|
||||
else if (m_xml.name() == "History") {
|
||||
if (history) {
|
||||
raiseError();
|
||||
}
|
||||
else {
|
||||
parseEntryHistory(entry);
|
||||
}
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseEntryString(Entry *entry)
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "String");
|
||||
|
||||
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 {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseEntryBinary(Entry *entry)
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Binary");
|
||||
|
||||
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 {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseAutoType(Entry* entry)
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "AutoType");
|
||||
|
||||
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(entry);
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseAutoTypeAssoc(Entry *entry)
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Association");
|
||||
|
||||
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 {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::parseEntryHistory(Entry* entry)
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "History");
|
||||
|
||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||
if (m_xml.name() == "Entry") {
|
||||
Entry* historyItem = parseEntry(true);
|
||||
entry->addHistoryItem(historyItem);
|
||||
}
|
||||
else {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TimeInfo KeePass2XmlReader::parseTimes()
|
||||
{
|
||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Times");
|
||||
|
||||
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 {
|
||||
skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
return timeInfo;
|
||||
}
|
||||
|
||||
QString KeePass2XmlReader::readString()
|
||||
{
|
||||
return m_xml.readElementText();
|
||||
}
|
||||
|
||||
bool KeePass2XmlReader::readBool()
|
||||
{
|
||||
QString str = readString();
|
||||
|
||||
if (str.compare("True", Qt::CaseInsensitive) == 0) {
|
||||
return true;
|
||||
}
|
||||
else if (str.compare("False", Qt::CaseInsensitive) == 0) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
raiseError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QDateTime KeePass2XmlReader::readDateTime()
|
||||
{
|
||||
QString str = readString();
|
||||
QDateTime dt = QDateTime::fromString(str, Qt::ISODate);
|
||||
|
||||
if (!dt.isValid()) {
|
||||
raiseError();
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
QColor KeePass2XmlReader::readColor()
|
||||
{
|
||||
QString colorStr = readString();
|
||||
|
||||
if (colorStr.isEmpty()) {
|
||||
return QColor();
|
||||
}
|
||||
|
||||
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, 16);
|
||||
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 KeePass2XmlReader::readNumber()
|
||||
{
|
||||
bool ok;
|
||||
int result = readString().toInt(&ok);
|
||||
if (!ok) {
|
||||
raiseError();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Uuid KeePass2XmlReader::readUuid()
|
||||
{
|
||||
QByteArray uuidBin = readBinary();
|
||||
if (uuidBin.length() != Uuid::length) {
|
||||
raiseError();
|
||||
return Uuid();
|
||||
}
|
||||
else {
|
||||
return Uuid(uuidBin);
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray KeePass2XmlReader::readBinary()
|
||||
{
|
||||
return QByteArray::fromBase64(readString().toAscii());
|
||||
}
|
||||
|
||||
Group* KeePass2XmlReader::getGroup(const Uuid& uuid)
|
||||
{
|
||||
if (uuid.isNull()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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* KeePass2XmlReader::getEntry(const Uuid& uuid)
|
||||
{
|
||||
if (uuid.isNull()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 KeePass2XmlReader::raiseError()
|
||||
{
|
||||
m_xml.raiseError(tr("Invalid database file"));
|
||||
}
|
||||
|
||||
void KeePass2XmlReader::skipCurrentElement()
|
||||
{
|
||||
qDebug() << "KeePass2XmlReader::skipCurrentElement(): skip: " << m_xml.name();
|
||||
m_xml.skipCurrentElement();
|
||||
}
|
||||
83
src/format/KeePass2XmlReader.h
Normal file
83
src/format/KeePass2XmlReader.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSX_PARSER_H
|
||||
#define KEEPASSX_PARSER_H
|
||||
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QXmlStreamReader>
|
||||
#include <QtGui/QColor>
|
||||
|
||||
#include "core/TimeInfo.h"
|
||||
#include "core/Uuid.h"
|
||||
|
||||
class Database;
|
||||
class Entry;
|
||||
class Group;
|
||||
class Metadata;
|
||||
|
||||
class KeePass2XmlReader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit KeePass2XmlReader(Database* db);
|
||||
bool parse(const QString& filename);
|
||||
QString errorMsg();
|
||||
|
||||
private:
|
||||
void parseKeePassFile();
|
||||
void parseMeta();
|
||||
void parseMemoryProtection();
|
||||
void parseCustomIcons();
|
||||
void parseIcon();
|
||||
void parseCustomData();
|
||||
void parseCustomDataItem();
|
||||
void parseRoot();
|
||||
Group* parseGroup();
|
||||
void parseDeletedObjects();
|
||||
void parseDeletedObject();
|
||||
Entry* parseEntry(bool history);
|
||||
void parseEntryString(Entry* entry);
|
||||
void parseEntryBinary(Entry* entry);
|
||||
void parseAutoType(Entry* entry);
|
||||
void parseAutoTypeAssoc(Entry* entry);
|
||||
void parseEntryHistory(Entry* entry);
|
||||
TimeInfo parseTimes();
|
||||
|
||||
QString readString();
|
||||
bool readBool();
|
||||
QDateTime readDateTime();
|
||||
QColor readColor();
|
||||
int readNumber();
|
||||
Uuid readUuid();
|
||||
QByteArray readBinary();
|
||||
|
||||
Group* getGroup(const Uuid& uuid);
|
||||
Entry* getEntry(const Uuid& uuid);
|
||||
void raiseError();
|
||||
void skipCurrentElement();
|
||||
|
||||
QXmlStreamReader m_xml;
|
||||
Database* m_db;
|
||||
Metadata* m_meta;
|
||||
Group* m_tmpParent;
|
||||
QList<Group*> m_groups;
|
||||
QList<Entry*> m_entries;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_PARSER_H
|
||||
394
src/format/KeePass2XmlWriter.cpp
Normal file
394
src/format/KeePass2XmlWriter.cpp
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "KeePass2XmlWriter.h"
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include "core/Metadata.h"
|
||||
|
||||
KeePass2XmlWriter::KeePass2XmlWriter(Database* db)
|
||||
: QObject(db)
|
||||
, m_db(db)
|
||||
, m_meta(db->metadata())
|
||||
{
|
||||
m_xml.setAutoFormatting(true);
|
||||
m_xml.setAutoFormattingIndent(-1); // 1 tab
|
||||
m_xml.setCodec("UTF-8");
|
||||
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::write(QIODevice* device)
|
||||
{
|
||||
m_xml.setDevice(device);
|
||||
|
||||
m_xml.writeStartDocument("1.0", true);
|
||||
|
||||
m_xml.writeStartElement("KeePassFile");
|
||||
|
||||
writeMetadata();
|
||||
writeRoot();
|
||||
|
||||
m_xml.writeEndElement();
|
||||
|
||||
m_xml.writeEndDocument();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::write(const QString& filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
write(&file);
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeMetadata()
|
||||
{
|
||||
m_xml.writeStartElement("Meta");
|
||||
|
||||
writeString("Generator", m_meta->generator());
|
||||
writeString("DatabaseName", m_meta->name());
|
||||
writeDateTime("DatabaseNameChanged", m_meta->nameChanged());
|
||||
writeString("DatabaseDescription", m_meta->description());
|
||||
writeDateTime("DatabaseDescriptionChanged", m_meta->descriptionChanged());
|
||||
writeString("DefaultUserName", m_meta->defaultUserName());
|
||||
writeDateTime("DefaultUserNameChanged", m_meta->defaultUserNameChanged());
|
||||
writeNumber("MaintenanceHistoryDays", m_meta->maintenanceHistoryDays());
|
||||
writeMemoryProtection();
|
||||
writeCustomIcons();
|
||||
writeBool("RecycleBinEnabled", m_meta->recycleBinEnabled());
|
||||
writeUuid("RecycleBinUUID", m_meta->recycleBin());
|
||||
writeDateTime("RecycleBinChanged", m_meta->recycleBinChanged());
|
||||
writeUuid("EntryTemplatesGroup", m_meta->entryTemplatesGroup());
|
||||
writeDateTime("EntryTemplatesGroupChanged", m_meta->entryTemplatesGroupChanged());
|
||||
writeUuid("LastSelectedGroup", m_meta->lastSelectedGroup());
|
||||
writeUuid("LastTopVisibleGroup", m_meta->lastTopVisibleGroup());
|
||||
writeCustomData();
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeMemoryProtection()
|
||||
{
|
||||
m_xml.writeStartElement("MemoryProtection");
|
||||
|
||||
writeBool("ProtectTitle", m_meta->protectTitle());
|
||||
writeBool("ProtectUserName", m_meta->protectUsername());
|
||||
writeBool("ProtectPassword", m_meta->protectPassword());
|
||||
writeBool("ProtectURL", m_meta->protectUrl());
|
||||
writeBool("ProtectNotes", m_meta->protectNotes());
|
||||
writeBool("AutoEnableVisualHiding", m_meta->autoEnableVisualHiding());
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeCustomIcons()
|
||||
{
|
||||
m_xml.writeStartElement("CustomIcons");
|
||||
|
||||
QHash<Uuid, QImage> customIcons = m_meta->customIcons();
|
||||
Q_FOREACH (const Uuid& uuid, customIcons.keys()) {
|
||||
writeIcon(uuid, customIcons.value(uuid));
|
||||
}
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeIcon(const Uuid& uuid, const QImage& image)
|
||||
{
|
||||
m_xml.writeStartElement("Icon");
|
||||
|
||||
writeUuid("UUID", uuid);
|
||||
|
||||
QByteArray ba;
|
||||
QBuffer buffer(&ba);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
image.save(&buffer, "PNG");
|
||||
buffer.close();
|
||||
writeBinary("Data", ba);
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeCustomData()
|
||||
{
|
||||
m_xml.writeStartElement("CustomData");
|
||||
|
||||
QHash<QString, QString> customFields = m_meta->customFields();
|
||||
Q_FOREACH (const QString& key, customFields.keys()) {
|
||||
writeCustomDataItem(key, customFields.value(key));
|
||||
}
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeCustomDataItem(const QString& key, const QString& value)
|
||||
{
|
||||
m_xml.writeStartElement("Item");
|
||||
|
||||
writeString("Key", key);
|
||||
writeString("Value", value);
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeRoot()
|
||||
{
|
||||
Q_ASSERT(m_db->rootGroup());
|
||||
|
||||
m_xml.writeStartElement("Root");
|
||||
|
||||
writeGroup(m_db->rootGroup());
|
||||
writeDeletedObjects();
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeGroup(const Group* group)
|
||||
{
|
||||
m_xml.writeStartElement("Group");
|
||||
|
||||
writeUuid("UUID", group->uuid());
|
||||
writeString("Name", group->name());
|
||||
writeNumber("IconID", group->iconNumber());
|
||||
|
||||
if (!group->iconUuid().isNull()) {
|
||||
writeUuid("CustomIconUUID", group->iconUuid());
|
||||
}
|
||||
writeTimes(group->timeInfo());
|
||||
writeBool("IsExpanded", group->isExpanded());
|
||||
writeString("DefaultAutoTypeSequence", group->defaultAutoTypeSequence());
|
||||
|
||||
int autoTypeEnabled = group->autoTypeEnabled();
|
||||
QString autoTypeEnabledStr;
|
||||
if (autoTypeEnabled == -1) {
|
||||
autoTypeEnabledStr = "null";
|
||||
}
|
||||
else if (autoTypeEnabled == 0) {
|
||||
autoTypeEnabledStr = "false";
|
||||
}
|
||||
else {
|
||||
autoTypeEnabledStr = "true";
|
||||
}
|
||||
writeString("EnableAutoType", autoTypeEnabledStr);
|
||||
|
||||
int searchingEnabed = group->searchingEnabed();
|
||||
QString searchingEnabedStr;
|
||||
if (searchingEnabed == -1) {
|
||||
searchingEnabedStr = "null";
|
||||
}
|
||||
else if (searchingEnabed == 0) {
|
||||
searchingEnabedStr = "false";
|
||||
}
|
||||
else {
|
||||
searchingEnabedStr = "true";
|
||||
}
|
||||
writeString("EnableSearching", searchingEnabedStr);
|
||||
|
||||
writeUuid("LastTopVisibleEntry", group->lastTopVisibleEntry());
|
||||
|
||||
Q_FOREACH (const Entry* entry, group->entries()) {
|
||||
writeEntry(entry);
|
||||
}
|
||||
|
||||
Q_FOREACH (const Group* child, group->children()) {
|
||||
writeGroup(child);
|
||||
}
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeTimes(const TimeInfo& ti)
|
||||
{
|
||||
m_xml.writeStartElement("Times");
|
||||
|
||||
writeDateTime("LastModificationTime", ti.lastModificationTime());
|
||||
writeDateTime("CreationTime", ti.creationTime());
|
||||
writeDateTime("LastAccessTime", ti.lastAccessTime());
|
||||
writeDateTime("ExpiryTime", ti.expiryTime());
|
||||
writeBool("Expires", ti.expires());
|
||||
writeNumber("UsageCount", ti.usageCount());
|
||||
writeDateTime("LocationChanged", ti.locationChanged());
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeDeletedObjects()
|
||||
{
|
||||
m_xml.writeStartElement("DeletedObjects");
|
||||
|
||||
Q_FOREACH (const DeletedObject& delObj, m_db->deletedObjects()) {
|
||||
writeDeletedObject(delObj);
|
||||
}
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeDeletedObject(const DeletedObject& delObj)
|
||||
{
|
||||
m_xml.writeStartElement("DeletedObject");
|
||||
|
||||
writeUuid("UUID", delObj.uuid);
|
||||
writeDateTime("DeletionTime", delObj.deletionTime);
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeEntry(const Entry* entry)
|
||||
{
|
||||
m_xml.writeStartElement("Entry");
|
||||
|
||||
writeUuid("UUID", entry->uuid());
|
||||
writeNumber("IconID", entry->iconNumber());
|
||||
if (!entry->iconUuid().isNull()) {
|
||||
writeUuid("CustomIconUUID", entry->iconUuid());
|
||||
}
|
||||
writeColor("ForegroundColor", entry->foregroundColor());
|
||||
writeColor("BackgroundColor", entry->backgroundColor());
|
||||
writeString("OverrideURL", entry->overrideUrl());
|
||||
writeTimes(entry->timeInfo());
|
||||
|
||||
Q_FOREACH (const QString& key, entry->attributes()) {
|
||||
m_xml.writeStartElement("String");
|
||||
writeString("Key", key);
|
||||
writeString("Value", entry->attributes().value(key));
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
Q_FOREACH (const QString& key, entry->attachments()) {
|
||||
m_xml.writeStartElement("Binary");
|
||||
writeString("Key", key);
|
||||
writeBinary("Value", entry->attachments().value(key));
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
writeAutoType(entry);
|
||||
writeEntryHistory(entry);
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeAutoType(const Entry* entry)
|
||||
{
|
||||
m_xml.writeStartElement("AutoType");
|
||||
|
||||
writeBool("Enabled", entry->autoTypeEnabled());
|
||||
writeNumber("DataTransferObfuscation", entry->autoTypeObfuscation());
|
||||
writeString("DefaultSequence", entry->defaultAutoTypeSequence());
|
||||
|
||||
Q_FOREACH (const AutoTypeAssociation& assoc, entry->autoTypeAssociations()) {
|
||||
writeAutoTypeAssoc(assoc);
|
||||
}
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeAutoTypeAssoc(const AutoTypeAssociation& assoc)
|
||||
{
|
||||
m_xml.writeStartElement("Association");
|
||||
|
||||
writeString("Window", assoc.window);
|
||||
writeString("KeystrokeSequence", assoc.sequence);
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeEntryHistory(const Entry* entry)
|
||||
{
|
||||
m_xml.writeStartElement("History");
|
||||
|
||||
const QList<Entry*>& historyItems = entry->historyItems();
|
||||
Q_FOREACH (const Entry* item, historyItems) {
|
||||
writeEntry(item);
|
||||
}
|
||||
|
||||
m_xml.writeEndElement();
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeString(const QString& qualifiedName, const QString& string)
|
||||
{
|
||||
m_xml.writeTextElement(qualifiedName, string);
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeNumber(const QString& qualifiedName, int number)
|
||||
{
|
||||
writeString(qualifiedName, QString::number(number));
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeBool(const QString& qualifiedName, bool b)
|
||||
{
|
||||
if (b) {
|
||||
writeString(qualifiedName, "True");
|
||||
}
|
||||
else {
|
||||
writeString(qualifiedName, "False");
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeDateTime(const QString& qualifiedName, const QDateTime& dateTime)
|
||||
{
|
||||
writeString(qualifiedName, dateTime.toUTC().toString(Qt::ISODate).append('Z'));
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeUuid(const QString& qualifiedName, const Uuid& uuid)
|
||||
{
|
||||
writeString(qualifiedName, uuid.toBase64());
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeUuid(const QString& qualifiedName, const Group* group)
|
||||
{
|
||||
if (group) {
|
||||
writeUuid(qualifiedName, group->uuid());
|
||||
}
|
||||
else {
|
||||
writeUuid(qualifiedName, Uuid());
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeUuid(const QString& qualifiedName, const Entry* entry)
|
||||
{
|
||||
if (entry) {
|
||||
writeUuid(qualifiedName, entry->uuid());
|
||||
}
|
||||
else {
|
||||
writeUuid(qualifiedName, Uuid());
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeBinary(const QString& qualifiedName, const QByteArray& ba)
|
||||
{
|
||||
writeString(qualifiedName, QString::fromAscii(ba.toBase64()));
|
||||
}
|
||||
|
||||
void KeePass2XmlWriter::writeColor(const QString& qualifiedName, const QColor& color)
|
||||
{
|
||||
QString colorStr = QString("#%1%2%3").arg(colorPartToString(color.red()))
|
||||
.arg(colorPartToString(color.green()))
|
||||
.arg(colorPartToString(color.blue()));
|
||||
|
||||
writeString(qualifiedName, colorStr);
|
||||
}
|
||||
|
||||
QString KeePass2XmlWriter::colorPartToString(int value)
|
||||
{
|
||||
QString str = QString::number(value, 16).toUpper();
|
||||
if (str.length() == 1) {
|
||||
str.prepend("0");
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
76
src/format/KeePass2XmlWriter.h
Normal file
76
src/format/KeePass2XmlWriter.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSX_WRITER_H
|
||||
#define KEEPASSX_WRITER_H
|
||||
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QXmlStreamWriter>
|
||||
#include <QtGui/QColor>
|
||||
#include <QtGui/QImage>
|
||||
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/TimeInfo.h"
|
||||
#include "core/Uuid.h"
|
||||
|
||||
class Group;
|
||||
class Metadata;
|
||||
|
||||
class KeePass2XmlWriter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KeePass2XmlWriter(Database* db);
|
||||
void write(QIODevice* device);
|
||||
void write(const QString& filename);
|
||||
|
||||
private:
|
||||
void writeMetadata();
|
||||
void writeMemoryProtection();
|
||||
void writeCustomIcons();
|
||||
void writeIcon(const Uuid& uuid, const QImage& image);
|
||||
void writeCustomData();
|
||||
void writeCustomDataItem(const QString& key, const QString& value);
|
||||
void writeRoot();
|
||||
void writeGroup(const Group* group);
|
||||
void writeTimes(const TimeInfo& ti);
|
||||
void writeDeletedObjects();
|
||||
void writeDeletedObject(const DeletedObject& delObj);
|
||||
void writeEntry(const Entry* entry);
|
||||
void writeAutoType(const Entry* entry);
|
||||
void writeAutoTypeAssoc(const AutoTypeAssociation& assoc);
|
||||
void writeEntryHistory(const Entry* entry);
|
||||
|
||||
void writeString(const QString& qualifiedName, const QString& string);
|
||||
void writeNumber(const QString& qualifiedName, int number);
|
||||
void writeBool(const QString& qualifiedName, bool b);
|
||||
void writeDateTime(const QString& qualifiedName, const QDateTime& dateTime);
|
||||
void writeUuid(const QString& qualifiedName, const Uuid& uuid);
|
||||
void writeUuid(const QString& qualifiedName, const Group* group);
|
||||
void writeUuid(const QString& qualifiedName, const Entry* entry);
|
||||
void writeBinary(const QString& qualifiedName, const QByteArray& ba);
|
||||
void writeColor(const QString& qualifiedName, const QColor& color);
|
||||
QString colorPartToString(int value);
|
||||
|
||||
QXmlStreamWriter m_xml;
|
||||
Database* m_db;
|
||||
Metadata* m_meta;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_WRITER_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue