1/*
2 Copyright (c) 2007 Till Adam <adam@kde.org>
3 Copyright (c) 2007 Volker Krause <vkrause@kde.org>
4
5 This library is free software; you can redistribute it and/or modify it
6 under the terms of the GNU Library General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or (at your
8 option) any later version.
9
10 This library is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 02110-1301, USA.
19*/
20
21#include "itemserializer_p.h"
22#include "item.h"
23#include "itemserializerplugin.h"
24#include "typepluginloader_p.h"
25#include "protocolhelper_p.h"
26
27// Qt
28#include <QtCore/QBuffer>
29#include <QtCore/QFile>
30#include <QtCore/QIODevice>
31#include <QtCore/QString>
32
33#include <string>
34
35Q_DECLARE_METATYPE(std::string)
36
37namespace Akonadi {
38
39DefaultItemSerializerPlugin::DefaultItemSerializerPlugin()
40{
41 Item::addToLegacyMapping<QByteArray>(QLatin1String("application/octet-stream"));
42}
43
44bool DefaultItemSerializerPlugin::deserialize(Item &item, const QByteArray &label, QIODevice &data, int)
45{
46 if (label != Item::FullPayload) {
47 return false;
48 }
49
50 item.setPayload(data.readAll());
51 return true;
52}
53
54void DefaultItemSerializerPlugin::serialize(const Item &item, const QByteArray &label, QIODevice &data, int &)
55{
56 Q_ASSERT(label == Item::FullPayload);
57 Q_UNUSED(label);
58 data.write(item.payload<QByteArray>());
59}
60
61bool StdStringItemSerializerPlugin::deserialize(Item &item, const QByteArray &label, QIODevice &data, int)
62{
63 if (label != Item::FullPayload) {
64 return false;
65 }
66 std::string str;
67 {
68 const QByteArray ba = data.readAll();
69 str.assign(ba.data(), ba.size());
70 }
71 item.setPayload(str);
72 return true;
73}
74
75void StdStringItemSerializerPlugin::serialize(const Item &item, const QByteArray &label, QIODevice &data, int &)
76{
77 Q_ASSERT(label == Item::FullPayload);
78 Q_UNUSED(label);
79 const std::string str = item.payload<std::string>();
80 data.write(QByteArray::fromRawData(str.data(), str.size()));
81}
82
83/*static*/
84void ItemSerializer::deserialize(Item &item, const QByteArray &label, const QByteArray &data, int version, bool external)
85{
86 if (external) {
87 const QString fileName = ProtocolHelper::absolutePayloadFilePath(QString::fromUtf8(data));
88 QFile file(fileName);
89 if (file.open(QIODevice::ReadOnly)) {
90 deserialize(item, label, file, version);
91 file.close();
92 } else {
93 kWarning() << "Failed to open external payload:" << fileName << file.errorString();
94 }
95 } else {
96 QBuffer buffer;
97 buffer.setData(data);
98 buffer.open(QIODevice::ReadOnly);
99 buffer.seek(0);
100 deserialize(item, label, buffer, version);
101 buffer.close();
102 }
103}
104
105/*static*/
106void ItemSerializer::deserialize(Item &item, const QByteArray &label, QIODevice &data, int version)
107{
108 if (!TypePluginLoader::defaultPluginForMimeType(item.mimeType())->deserialize(item, label, data, version)) {
109 kWarning() << "Unable to deserialize payload part:" << label;
110 data.seek(0);
111 kWarning() << "Payload data was: " << data.readAll();
112 }
113}
114
115/*static*/
116void ItemSerializer::serialize(const Item &item, const QByteArray &label, QByteArray &data, int &version)
117{
118 QBuffer buffer;
119 buffer.setBuffer(&data);
120 buffer.open(QIODevice::WriteOnly);
121 buffer.seek(0);
122 serialize(item, label, buffer, version);
123 buffer.close();
124}
125
126/*static*/
127void ItemSerializer::serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version)
128{
129 if (!item.hasPayload()) {
130 return;
131 }
132 ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds());
133 plugin->serialize(item, label, data, version);
134}
135
136void ItemSerializer::apply(Item &item, const Item &other)
137{
138 if (!other.hasPayload()) {
139 return;
140 }
141
142 ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds());
143
144 ItemSerializerPluginV2 *pluginV2 = dynamic_cast<ItemSerializerPluginV2 *>(plugin);
145 if (pluginV2) {
146 pluginV2->apply(item, other);
147 return;
148 }
149
150 // Old-school merge:
151 foreach (const QByteArray &part, other.loadedPayloadParts()) {
152 QByteArray partData;
153 QBuffer buffer;
154 buffer.setBuffer(&partData);
155 buffer.open(QIODevice::ReadWrite);
156 buffer.seek(0);
157 int version;
158 serialize(other, part, buffer, version);
159 buffer.seek(0);
160 deserialize(item, part, buffer, version);
161 }
162}
163
164QSet<QByteArray> ItemSerializer::parts(const Item &item)
165{
166 if (!item.hasPayload()) {
167 return QSet<QByteArray>();
168 }
169 return TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds())->parts(item);
170}
171
172QSet<QByteArray> ItemSerializer::availableParts(const Item &item)
173{
174 if (!item.hasPayload()) {
175 return QSet<QByteArray>();
176 }
177 ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds());
178 ItemSerializerPluginV2 *pluginV2 = dynamic_cast<ItemSerializerPluginV2 *>(plugin);
179
180 if (pluginV2) {
181 return pluginV2->availableParts(item);
182 }
183
184 if (item.hasPayload()) {
185 return QSet<QByteArray>();
186 }
187
188 return QSet<QByteArray>() << Item::FullPayload;
189}
190
191Item ItemSerializer::convert(const Item &item, int mtid)
192{
193// kDebug() << "asked to convert a" << item.mimeType() << "item to format" << ( mtid ? QMetaType::typeName( mtid ) : "<legacy>" );
194 if (!item.hasPayload()) {
195 kDebug() << " -> but item has no payload!";
196 return Item();
197 }
198
199 if (ItemSerializerPlugin *const plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), QVector<int>(1, mtid), TypePluginLoader::NoDefault)) {
200 kDebug() << " -> found a plugin that feels responsible, trying serialising the payload";
201 QBuffer buffer;
202 buffer.open(QIODevice::ReadWrite);
203 int version;
204 serialize(item, Item::FullPayload, buffer, version);
205 buffer.seek(0);
206 kDebug() << " -> serialized payload into" << buffer.size() << "bytes" << endl
207 << " -> going to deserialize";
208 Item newItem;
209 if (plugin->deserialize(newItem, Item::FullPayload, buffer, version)) {
210 kDebug() << " -> conversion successful";
211 return newItem;
212 } else {
213 kDebug() << " -> conversion FAILED";
214 }
215 } else {
216// kDebug() << " -> found NO plugin that feels responsible";
217 }
218 return Item();
219}
220
221void ItemSerializer::overridePluginLookup(QObject *p)
222{
223 TypePluginLoader::overridePluginLookup(p);
224}
225
226}
227