1 /* 2 SPDX-FileCopyrightText: 2015-2017 Krzysztof Nowicki <krissn@op.pl> 3 4 SPDX-License-Identifier: LGPL-2.0-or-later 5 */ 6 7 #pragma once 8 9 #include <functional> 10 11 #include <QVector> 12 #include <QXmlStreamReader> 13 14 #include "ewsclient_debug.h" 15 16 template<typename T> class EwsXml 17 { 18 public: 19 typedef std::function<bool(QXmlStreamReader &, QVariant &)> ReadFunction; 20 typedef std::function<bool(QXmlStreamWriter &, const QVariant &)> WriteFunction; 21 typedef std::function<bool(QXmlStreamReader &, const QString &)> UnknownElementFunction; 22 23 typedef QHash<T, QVariant> ValueHash; 24 25 static constexpr T Ignore = static_cast<T>(-1); 26 27 struct Item { ItemItem28 Item() 29 : key(Ignore) 30 { 31 } 32 33 Item(T k, const QString &n, const ReadFunction &rfn = ReadFunction(), const WriteFunction &wfn = WriteFunction()) keyItem34 : key(k) 35 , elmName(n) 36 , readFn(rfn) 37 , writeFn(wfn) 38 { 39 } 40 41 T key; 42 QString elmName; 43 ReadFunction readFn; 44 WriteFunction writeFn; 45 }; 46 EwsXml()47 EwsXml() 48 { 49 } 50 EwsXml(const QVector<Item> & items)51 EwsXml(const QVector<Item> &items) 52 : mItems(items) 53 { 54 rebuildItemHash(); 55 } 56 EwsXml(const EwsXml & other)57 EwsXml(const EwsXml &other) 58 : mItems(other.mItems) 59 , mValues(other.mValues) 60 , mItemHash(other.mItemHash) 61 { 62 } 63 setItems(const QVector<Item> & items)64 void setItems(const QVector<Item> &items) 65 { 66 mItems = items; 67 rebuildItemHash(); 68 } 69 70 bool readItem(QXmlStreamReader &reader, const QString &parentElm, const QString &nsUri, UnknownElementFunction unknownElmFn = &defaultUnknownElmFunction) 71 { 72 typename QHash<QString, Item>::iterator it = mItemHash.find(reader.name().toString()); 73 if (it != mItemHash.end() && nsUri == reader.namespaceUri()) { 74 if (it->key == Ignore) { 75 qCInfoNC(EWSCLI_LOG) << QStringLiteral("Unsupported %1 child element %2 - ignoring.").arg(parentElm).arg(reader.name().toString()); 76 reader.skipCurrentElement(); 77 return true; 78 } else if (!it->readFn) { 79 qCWarning(EWSCLI_LOG) 80 << QStringLiteral("Failed to read %1 element - no read support for %2 element.").arg(parentElm).arg(reader.name().toString()); 81 return false; 82 } else { 83 QVariant val = mValues[it->key]; 84 if (it->readFn(reader, val)) { 85 mValues[it->key] = val; 86 return true; 87 } 88 return false; 89 } 90 } 91 return unknownElmFn(reader, parentElm); 92 } 93 94 bool readItems(QXmlStreamReader &reader, const QString &nsUri, const UnknownElementFunction &unknownElmFn = &defaultUnknownElmFunction) 95 { 96 QString elmName(reader.name().toString()); 97 while (reader.readNextStartElement()) { 98 if (!readItem(reader, elmName, nsUri, unknownElmFn)) { 99 return false; 100 } 101 } 102 return true; 103 } 104 105 bool writeItems(QXmlStreamWriter &writer, 106 const QString &parentElm, 107 const QString &nsUri, 108 const ValueHash &values, 109 const QList<T> &keysToWrite = QList<T>()) const 110 { 111 bool hasKeysToWrite = !keysToWrite.isEmpty(); 112 for (const Item &item : std::as_const(mItems)) { 113 if (!hasKeysToWrite || keysToWrite.contains(item.key)) { 114 typename ValueHash::const_iterator it = values.find(item.key); 115 if (it != values.end()) { 116 if (!item.writeFn) { 117 qCWarning(EWSCLI_LOG) 118 << QStringLiteral("Failed to write %1 element - no write support for %2 element.").arg(parentElm).arg(item.elmName); 119 return false; 120 } 121 writer.writeStartElement(nsUri, item.elmName); 122 bool status = item.writeFn(writer, *it); 123 writer.writeEndElement(); 124 if (!status) { 125 return false; 126 } 127 } 128 } 129 } 130 return true; 131 } 132 values()133 ValueHash values() const 134 { 135 return mValues; 136 } 137 138 private: defaultUnknownElmFunction(QXmlStreamReader & reader,const QString & parentElm)139 static bool defaultUnknownElmFunction(QXmlStreamReader &reader, const QString &parentElm) 140 { 141 qCWarning(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid %2 element.").arg(parentElm).arg(reader.name().toString()); 142 return false; 143 } 144 145 const QVector<Item> mItems; 146 ValueHash mValues; 147 QHash<QString, Item> mItemHash; 148 rebuildItemHash()149 void rebuildItemHash() 150 { 151 for (const Item &item : std::as_const(mItems)) { 152 mItemHash.insert(item.elmName, item); 153 } 154 } 155 }; 156 157 template<typename T> T readXmlElementValue(QXmlStreamReader &reader, bool &ok, const QString &parentElement); 158 159 extern bool ewsXmlBoolReader(QXmlStreamReader &reader, QVariant &val); 160 extern bool ewsXmlBoolWriter(QXmlStreamWriter &writer, const QVariant &val); 161 extern bool ewsXmlBase64Reader(QXmlStreamReader &reader, QVariant &val); 162 extern bool ewsXmlBase64Writer(QXmlStreamWriter &writer, const QVariant &val); 163 extern bool ewsXmlIdReader(QXmlStreamReader &reader, QVariant &val); 164 extern bool ewsXmlIdWriter(QXmlStreamWriter &writer, const QVariant &val); 165 extern bool ewsXmlTextReader(QXmlStreamReader &reader, QVariant &val); 166 extern bool ewsXmlTextWriter(QXmlStreamWriter &writer, const QVariant &val); 167 extern bool ewsXmlUIntReader(QXmlStreamReader &reader, QVariant &val); 168 extern bool ewsXmlUIntWriter(QXmlStreamWriter &writer, const QVariant &val); 169 extern bool ewsXmlDateTimeReader(QXmlStreamReader &reader, QVariant &val); 170 extern bool ewsXmlItemReader(QXmlStreamReader &reader, QVariant &val); 171 extern bool ewsXmlFolderReader(QXmlStreamReader &reader, QVariant &val); 172 173 extern bool ewsXmlEnumReader(QXmlStreamReader &reader, QVariant &val, const QVector<QString> &items); 174 extern bool ewsXmlSensitivityReader(QXmlStreamReader &reader, QVariant &val); 175 extern bool ewsXmlImportanceReader(QXmlStreamReader &reader, QVariant &val); 176 extern bool ewsXmlCalendarItemTypeReader(QXmlStreamReader &reader, QVariant &val); 177 extern bool ewsXmlLegacyFreeBusyStatusReader(QXmlStreamReader &reader, QVariant &val); 178 extern bool ewsXmlResponseTypeReader(QXmlStreamReader &reader, QVariant &val); 179 180