Akonadi

itemserializer.cpp
1/*
2 SPDX-FileCopyrightText: 2007 Till Adam <adam@kde.org>
3 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org>
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
28Q_DECLARE_METATYPE(std::string)
29
30namespace Akonadi
31{
32DefaultItemSerializerPlugin::DefaultItemSerializerPlugin() = default;
33
34bool 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
44void 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
52bool 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
66void 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*/
76void 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);
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) {
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*/
103void 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*/
139void ItemSerializer::serialize(const Item &item, const QByteArray &label, QByteArray &data, int &version)
140{
141 QBuffer buffer;
142 buffer.setBuffer(&data);
144 buffer.seek(0);
145 serialize(item, label, buffer, version);
146 buffer.close();
147}
148
149/*static*/
150void 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
166void 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
176QSet<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
184QSet<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
193QSet<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
203Item ItemSerializer::convert(const Item &item, int mtid)
204{
205 qCDebug(AKONADICORE_LOG) << "asked to convert a" << item.mimeType() << "item to format" << (mtid ? QMetaType(mtid).name() : "<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(), QList<int>(1, mtid), TypePluginLoader::NoDefault)) {
212 qCDebug(AKONADICORE_LOG) << " -> found a plugin that feels responsible, trying serialising the payload";
213 QBuffer buffer;
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
233void ItemSerializer::overridePluginLookup(QObject *p)
234{
235 TypePluginLoader::overridePluginLookup(p);
236}
237
238} // namespace Akonadi
239
240#include "moc_itemserializer_p.cpp"
static const char FullPayload[]
Describes the part name that is used to fetch the full payload of an item.
Definition item.h:127
Helper integration between Akonadi and Qt.
KDB_EXPORT KDbVersionInfo version()
QString label(StandardShortcut id)
virtual void close() override
virtual bool open(OpenMode flags) override
virtual bool seek(qint64 pos) override
void setBuffer(QByteArray *byteArray)
void setData(const QByteArray &data)
virtual qint64 size() const const override
QByteArray & assign(InputIterator first, InputIterator last)
char * data()
QByteArray fromRawData(const char *data, qsizetype size)
qsizetype size() const const
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
virtual void close() override
QByteArray readAll()
virtual bool seek(qint64 pos)
qint64 write(const QByteArray &data)
const char * name() const const
QString fromStdString(const std::string &str)
QString fromUtf8(QByteArrayView str)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.