Akonadi

itemserializer.cpp
1 /*
2  SPDX-FileCopyrightText: 2007 Till Adam <[email protected]>
3  SPDX-FileCopyrightText: 2007 Volker Krause <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "config_p.h"
9 #include "item.h"
10 #include "itemserializer_p.h"
11 #include "itemserializerplugin.h"
12 #include "protocolhelper_p.h"
13 #include "typepluginloader_p.h"
14 
15 #include "private/compressionstream_p.h"
16 #include "private/externalpartstorage_p.h"
17 
18 #include "akonadicore_debug.h"
19 
20 // Qt
21 #include <QBuffer>
22 #include <QFile>
23 #include <QIODevice>
24 #include <QString>
25 
26 #include <string>
27 
28 Q_DECLARE_METATYPE(std::string)
29 
30 namespace Akonadi
31 {
32 DefaultItemSerializerPlugin::DefaultItemSerializerPlugin() = default;
33 
34 bool DefaultItemSerializerPlugin::deserialize(Item &item, const QByteArray &label, QIODevice &data, int /*version*/)
35 {
36  if (label != Item::FullPayload) {
37  return false;
38  }
39 
40  item.setPayload(data.readAll());
41  return true;
42 }
43 
44 void DefaultItemSerializerPlugin::serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version)
45 {
46  Q_UNUSED(version)
47  Q_ASSERT(label == Item::FullPayload);
48  Q_UNUSED(label)
49  data.write(item.payload<QByteArray>());
50 }
51 
52 bool StdStringItemSerializerPlugin::deserialize(Item &item, const QByteArray &label, QIODevice &data, int /*version*/)
53 {
54  if (label != Item::FullPayload) {
55  return false;
56  }
57  std::string str;
58  {
59  const QByteArray ba = data.readAll();
60  str.assign(ba.data(), ba.size());
61  }
62  item.setPayload(str);
63  return true;
64 }
65 
66 void StdStringItemSerializerPlugin::serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version)
67 {
68  Q_UNUSED(version)
69  Q_ASSERT(label == Item::FullPayload);
70  Q_UNUSED(label)
71  const auto str = item.payload<std::string>();
72  data.write(QByteArray::fromRawData(str.data(), str.size()));
73 }
74 
75 /*static*/
76 void ItemSerializer::deserialize(Item &item, const QByteArray &label, const QByteArray &data, int version, PayloadStorage storage)
77 {
78  if (storage == Internal) {
79  QBuffer buffer;
80  buffer.setData(data);
81  buffer.open(QIODevice::ReadOnly);
82  deserialize(item, label, buffer, version);
83  buffer.close();
84  } else {
85  QFile file;
86  if (storage == External) {
87  file.setFileName(ExternalPartStorage::resolveAbsolutePath(data));
88  } else if (storage == Foreign) {
89  file.setFileName(QString::fromUtf8(data));
90  }
91 
92  if (file.open(QIODevice::ReadOnly)) {
93  deserialize(item, label, file, version);
94  file.close();
95  } else {
96  qCWarning(AKONADICORE_LOG) << "Failed to open" << ((storage == External) ? "external" : "foreign") << "payload:" << file.fileName()
97  << file.errorString();
98  }
99  }
100 }
101 
102 /*static*/
103 void ItemSerializer::deserialize(Item &item, const QByteArray &label, QIODevice &data, int version)
104 {
105  auto plugin = TypePluginLoader::defaultPluginForMimeType(item.mimeType());
106 
107  const auto handleError = [&](QIODevice &device, bool compressed) {
108  device.seek(0);
109  QByteArray data;
110  if (compressed) {
111  CompressionStream decompressor(&device);
112  decompressor.open(QIODevice::ReadOnly);
113  data = decompressor.readAll();
114  } else {
115  data = device.readAll();
116  }
117 
118  qCWarning(AKONADICORE_LOG) << "Unable to deserialize payload part:" << label << "in item" << item.id() << "collection" << item.parentCollection().id();
119  qCWarning(AKONADICORE_LOG) << (compressed ? "Decompressed" : "") << "payload data was: " << data;
120  };
121 
122  if (CompressionStream::isCompressed(&data)) {
123  CompressionStream decompressor(&data);
124  decompressor.open(QIODevice::ReadOnly);
125  if (!plugin->deserialize(item, label, decompressor, version)) {
126  handleError(data, true);
127  }
128  if (decompressor.error()) {
129  qCWarning(AKONADICORE_LOG) << "Deserialization failed due to decompression error:" << QString::fromStdString(decompressor.error().message());
130  }
131  } else {
132  if (!plugin->deserialize(item, label, data, version)) {
133  handleError(data, false);
134  }
135  }
136 }
137 
138 /*static*/
139 void ItemSerializer::serialize(const Item &item, const QByteArray &label, QByteArray &data, int &version)
140 {
141  QBuffer buffer;
142  buffer.setBuffer(&data);
143  buffer.open(QIODevice::WriteOnly);
144  buffer.seek(0);
145  serialize(item, label, buffer, version);
146  buffer.close();
147 }
148 
149 /*static*/
150 void ItemSerializer::serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version)
151 {
152  if (!item.hasPayload()) {
153  return;
154  }
155  ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds());
156 
157  if (Config::get().payloadCompression.enabled) {
158  CompressionStream compressor(&data);
159  compressor.open(QIODevice::WriteOnly);
160  plugin->serialize(item, label, compressor, version);
161  } else {
162  plugin->serialize(item, label, data, version);
163  }
164 }
165 
166 void ItemSerializer::apply(Item &item, const Item &other)
167 {
168  if (!other.hasPayload()) {
169  return;
170  }
171 
172  ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds());
173  plugin->apply(item, other);
174 }
175 
176 QSet<QByteArray> ItemSerializer::parts(const Item &item)
177 {
178  if (!item.hasPayload()) {
179  return QSet<QByteArray>();
180  }
181  return TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds())->parts(item);
182 }
183 
184 QSet<QByteArray> ItemSerializer::availableParts(const Item &item)
185 {
186  if (!item.hasPayload()) {
187  return QSet<QByteArray>();
188  }
189  ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds());
190  return plugin->availableParts(item);
191 }
192 
193 QSet<QByteArray> ItemSerializer::allowedForeignParts(const Item &item)
194 {
195  if (!item.hasPayload()) {
196  return QSet<QByteArray>();
197  }
198 
199  ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds());
200  return plugin->allowedForeignParts(item);
201 }
202 
203 Item ItemSerializer::convert(const Item &item, int mtid)
204 {
205  qCDebug(AKONADICORE_LOG) << "asked to convert a" << item.mimeType() << "item to format" << (mtid ? QMetaType::typeName(mtid) : "<legacy>");
206  if (!item.hasPayload()) {
207  qCDebug(AKONADICORE_LOG) << " -> but item has no payload!";
208  return Item();
209  }
210 
211  if (ItemSerializerPlugin *const plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), QVector<int>(1, mtid), TypePluginLoader::NoDefault)) {
212  qCDebug(AKONADICORE_LOG) << " -> found a plugin that feels responsible, trying serialising the payload";
213  QBuffer buffer;
214  buffer.open(QIODevice::ReadWrite);
215  int version = 0;
216  serialize(item, Item::FullPayload, buffer, version);
217  buffer.seek(0);
218  qCDebug(AKONADICORE_LOG) << " -> serialized payload into" << buffer.size() << "bytes\n"
219  << " -> going to deserialize";
220  Item newItem;
221  if (plugin->deserialize(newItem, Item::FullPayload, buffer, version)) {
222  qCDebug(AKONADICORE_LOG) << " -> conversion successful";
223  return newItem;
224  } else {
225  qCDebug(AKONADICORE_LOG) << " -> conversion FAILED";
226  }
227  } else {
228  // qCDebug(AKONADICORE_LOG) << " -> found NO plugin that feels responsible";
229  }
230  return Item();
231 }
232 
233 void ItemSerializer::overridePluginLookup(QObject *p)
234 {
235  TypePluginLoader::overridePluginLookup(p);
236 }
237 
238 } // namespace Akonadi
QString errorString() const const
virtual bool open(QIODevice::OpenMode flags) override
QString fromUtf8(const char *str, int size)
QByteArray fromRawData(const char *data, int size)
virtual bool open(QIODevice::OpenMode mode) override
static const char FullPayload[]
Describes the part name that is used to fetch the full payload of an item.
Definition: item.h:131
virtual bool seek(qint64 pos)
virtual QString fileName() const const override
QString fromStdString(const std::string &str)
void setBuffer(QByteArray *byteArray)
virtual bool seek(qint64 pos) override
const char * typeName(int typeId)
void setFileName(const QString &name)
virtual void close() override
virtual void close() override
virtual qint64 size() const const override
void setData(const QByteArray &data)
QString label(StandardShortcut id)
unsigned int version()
int size() const const
QByteArray readAll()
char * data()
qint64 write(const char *data, qint64 maxSize)
virtual QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName)
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jul 2 2022 06:41:48 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.