~ubuntu-branches/ubuntu/trusty/kdepimlibs/trusty

« back to all changes in this revision

Viewing changes to akonadi/xml/xmldocument.cpp

  • Committer: Package Import Robot
  • Author(s): Rohan Garg, Rohan Garg, Philip Muškovac
  • Date: 2013-11-23 17:36:44 UTC
  • mfrom: (1.1.102)
  • Revision ID: package-import@ubuntu.com-20131123173644-p5ow94192ezsny8g
Tags: 4:4.11.80-0ubuntu1
[ Rohan Garg ]
* New upstream beta release
  - Bump akonadi requirement to 1.10.45
  - Update install files
  - Update symbols

[ Philip Muškovac ]
* kdepimlibs-dev/-dbg breaks/replaces kdepim-runtime/-dbg (<< 4:4.11.80)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (c) 2009 Volker Krause <vkrause@kde.org>
 
3
 
 
4
    This library is free software; you can redistribute it and/or modify it
 
5
    under the terms of the GNU Library General Public License as published by
 
6
    the Free Software Foundation; either version 2 of the License, or (at your
 
7
    option) any later version.
 
8
 
 
9
    This library is distributed in the hope that it will be useful, but WITHOUT
 
10
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
11
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
 
12
    License for more details.
 
13
 
 
14
    You should have received a copy of the GNU Library General Public License
 
15
    along with this library; see the file COPYING.LIB.  If not, write to the
 
16
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
17
    02110-1301, USA.
 
18
*/
 
19
 
 
20
#include "xmldocument.h"
 
21
#include "format_p.h"
 
22
#include "xmlreader.h"
 
23
 
 
24
#include <KDebug>
 
25
#include <KGlobal>
 
26
#include <KLocale>
 
27
#include <KStandardDirs>
 
28
 
 
29
#include <qdom.h>
 
30
#include <qfile.h>
 
31
 
 
32
#ifdef HAVE_LIBXML2
 
33
#include <libxml/parser.h>
 
34
#include <libxml/xmlIO.h>
 
35
#include <libxml/xmlschemas.h>
 
36
#endif
 
37
 
 
38
static const KCatalogLoader loader( QLatin1String( "libakonadi-xml") );
 
39
 
 
40
using namespace Akonadi;
 
41
 
 
42
// helper class for dealing with libxml resource management
 
43
template <typename T, void FreeFunc(T)> class XmlPtr
 
44
{
 
45
  public:
 
46
    XmlPtr( const T &t ) : p( t ) {}
 
47
 
 
48
    ~XmlPtr()
 
49
    {
 
50
      FreeFunc( p );
 
51
    }
 
52
 
 
53
    operator T() const
 
54
    {
 
55
      return p;
 
56
    }
 
57
 
 
58
    operator bool() const
 
59
    {
 
60
      return p != 0;
 
61
    }
 
62
 
 
63
  private:
 
64
    T p;
 
65
};
 
66
 
 
67
static QDomElement findElementByRidHelper( const QDomElement &elem, const QString &rid, const QString &elemName )
 
68
{
 
69
  if ( elem.isNull() )
 
70
    return QDomElement();
 
71
  if ( elem.tagName() == elemName && elem.attribute( Format::Attr::remoteId() ) == rid )
 
72
    return elem;
 
73
  const QDomNodeList children = elem.childNodes();
 
74
  for ( int i = 0; i < children.count(); ++i ) {
 
75
    const QDomElement child = children.at( i ).toElement();
 
76
    if ( child.isNull() )
 
77
      continue;
 
78
    const QDomElement rv = findElementByRidHelper( child, rid, elemName );
 
79
    if ( !rv.isNull() )
 
80
      return rv;
 
81
  }
 
82
  return QDomElement();
 
83
}
 
84
 
 
85
namespace Akonadi {
 
86
 
 
87
class XmlDocumentPrivate
 
88
{
 
89
  public:
 
90
    XmlDocumentPrivate() :
 
91
      valid( false )
 
92
    {
 
93
      lastError = i18n( "No data loaded." );
 
94
    }
 
95
 
 
96
    QDomElement findElementByRid( const QString &rid, const QString &elemName ) const
 
97
    {
 
98
      return findElementByRidHelper( document.documentElement(), rid, elemName );
 
99
    }
 
100
 
 
101
    QDomDocument document;
 
102
    QString lastError;
 
103
    bool valid;
 
104
};
 
105
 
 
106
}
 
107
 
 
108
XmlDocument::XmlDocument() :
 
109
  d( new XmlDocumentPrivate )
 
110
{
 
111
  const QDomElement rootElem = d->document.createElement( Format::Tag::root() );
 
112
  d->document.appendChild( rootElem );
 
113
}
 
114
 
 
115
XmlDocument::XmlDocument(const QString& fileName) :
 
116
  d( new XmlDocumentPrivate )
 
117
{
 
118
  loadFile( fileName );
 
119
}
 
120
 
 
121
XmlDocument::~XmlDocument()
 
122
{
 
123
  delete d;
 
124
}
 
125
 
 
126
bool Akonadi::XmlDocument::loadFile(const QString& fileName)
 
127
{
 
128
  d->valid = false;
 
129
  d->document = QDomDocument();
 
130
 
 
131
  if ( fileName.isEmpty() ) {
 
132
    d->lastError = i18n( "No filename specified" );
 
133
    return false;
 
134
  }
 
135
 
 
136
  QFile file( fileName );
 
137
  QByteArray data;
 
138
  if ( file.exists() ) {
 
139
    if ( !file.open( QIODevice::ReadOnly ) ) {
 
140
      d->lastError = i18n( "Unable to open data file '%1'.", fileName );
 
141
      return false;
 
142
    }
 
143
    data = file.readAll();
 
144
  } else {
 
145
    d->lastError = i18n( "File %1 does not exist.", fileName );
 
146
    return false;
 
147
  }
 
148
 
 
149
#ifdef HAVE_LIBXML2
 
150
  // schema validation
 
151
  XmlPtr<xmlDocPtr, xmlFreeDoc> sourceDoc( xmlParseMemory( data.constData(), data.length() ) );
 
152
  if ( !sourceDoc ) {
 
153
    d->lastError = i18n( "Unable to parse data file '%1'.", fileName );
 
154
    return false;
 
155
  }
 
156
 
 
157
  const QString &schemaFileName = KGlobal::dirs()->findResource( "data", QLatin1String("akonadi/akonadi-xml.xsd") );
 
158
  XmlPtr<xmlDocPtr, xmlFreeDoc> schemaDoc( xmlReadFile( schemaFileName.toLocal8Bit(), 0, XML_PARSE_NONET ) );
 
159
  if ( !schemaDoc ) {
 
160
    d->lastError = i18n( "Schema definition could not be loaded and parsed." );
 
161
    return false;
 
162
  }
 
163
  XmlPtr<xmlSchemaParserCtxtPtr, xmlSchemaFreeParserCtxt> parserContext( xmlSchemaNewDocParserCtxt( schemaDoc ) );
 
164
  if ( !parserContext ) {
 
165
    d->lastError = i18n( "Unable to create schema parser context." );
 
166
    return false;
 
167
  }
 
168
  XmlPtr<xmlSchemaPtr, xmlSchemaFree> schema( xmlSchemaParse( parserContext ) );
 
169
  if ( !schema ) {
 
170
    d->lastError = i18n( "Unable to create schema." );
 
171
    return false;
 
172
  }
 
173
  XmlPtr<xmlSchemaValidCtxtPtr, xmlSchemaFreeValidCtxt> validationContext( xmlSchemaNewValidCtxt( schema ) );
 
174
  if ( !validationContext ) {
 
175
    d->lastError = i18n( "Unable to create schema validation context." );
 
176
    return false;
 
177
  }
 
178
 
 
179
  if ( xmlSchemaValidateDoc( validationContext, sourceDoc ) != 0 ) {
 
180
    d->lastError = i18n( "Invalid file format." );
 
181
    return false;
 
182
  }
 
183
#endif
 
184
 
 
185
  // DOM loading
 
186
  QString errMsg;
 
187
  if ( !d->document.setContent( data, true, &errMsg ) ) {
 
188
    d->lastError = i18n( "Unable to parse data file: %1", errMsg );
 
189
    return false;
 
190
  }
 
191
 
 
192
  d->valid = true;
 
193
  d->lastError.clear();
 
194
  return true;
 
195
}
 
196
 
 
197
bool XmlDocument::writeToFile(const QString& fileName) const
 
198
{
 
199
  QFile f( fileName );
 
200
  if ( !f.open( QFile::WriteOnly ) ) {
 
201
    d->lastError = f.errorString();
 
202
    return false;
 
203
  }
 
204
 
 
205
  f.write( d->document.toByteArray( 2 ) );
 
206
 
 
207
  d->lastError.clear();
 
208
  return true;
 
209
}
 
210
 
 
211
bool XmlDocument::isValid() const
 
212
{
 
213
  return d->valid;
 
214
}
 
215
 
 
216
QString XmlDocument::lastError() const
 
217
{
 
218
  return d->lastError;
 
219
}
 
220
 
 
221
QDomDocument& XmlDocument::document() const
 
222
{
 
223
  return d->document;
 
224
}
 
225
 
 
226
QDomElement XmlDocument::collectionElementByRemoteId(const QString& rid) const
 
227
{
 
228
  return d->findElementByRid( rid, Format::Tag::collection() );
 
229
}
 
230
 
 
231
QDomElement XmlDocument::collectionElement( const Collection &collection ) const
 
232
{
 
233
  if ( collection == Collection::root() )
 
234
    return d->document.documentElement();
 
235
  if ( collection.remoteId().isEmpty() )
 
236
    return QDomElement();
 
237
  if ( collection.parentCollection().remoteId().isEmpty() && collection.parentCollection() != Collection::root() )
 
238
    return d->findElementByRid( collection.remoteId(), Format::Tag::collection() );
 
239
  QDomElement parent = collectionElement( collection.parentCollection() );
 
240
  if ( parent.isNull() )
 
241
    return QDomElement();
 
242
  const QDomNodeList children = parent.childNodes();
 
243
  for ( int i = 0; i < children.count(); ++i ) {
 
244
    const QDomElement child = children.at( i ).toElement();
 
245
    if ( child.isNull() )
 
246
      continue;
 
247
   if ( child.tagName() == Format::Tag::collection() && child.attribute( Format::Attr::remoteId() ) == collection.remoteId() )
 
248
    return child;
 
249
  }
 
250
  return QDomElement();
 
251
}
 
252
 
 
253
QDomElement XmlDocument::itemElementByRemoteId(const QString& rid) const
 
254
{
 
255
  return d->findElementByRid( rid, Format::Tag::item() );
 
256
}
 
257
 
 
258
Collection XmlDocument::collectionByRemoteId(const QString& rid) const
 
259
{
 
260
  const QDomElement elem = collectionElementByRemoteId( rid );
 
261
  return XmlReader::elementToCollection( elem );
 
262
}
 
263
 
 
264
Item XmlDocument::itemByRemoteId(const QString& rid, bool includePayload) const
 
265
{
 
266
  return XmlReader::elementToItem( itemElementByRemoteId( rid ), includePayload );
 
267
}
 
268
 
 
269
Collection::List XmlDocument::collections() const
 
270
{
 
271
  return XmlReader::readCollections( d->document.documentElement() );
 
272
}
 
273
 
 
274
Collection::List XmlDocument::childCollections(const QString& parentCollectionRid) const
 
275
{
 
276
  Collection c;
 
277
  c.setRemoteId( parentCollectionRid );
 
278
  return childCollections( c );
 
279
}
 
280
 
 
281
Collection::List XmlDocument::childCollections( const Collection &parentCollection ) const
 
282
{
 
283
  QDomElement parentElem = collectionElement( parentCollection );
 
284
 
 
285
  if ( parentElem.isNull() ) {
 
286
    d->lastError = QLatin1String( "Parent node not found." );
 
287
    return Collection::List();
 
288
  }
 
289
 
 
290
  Collection::List rv;
 
291
  const QDomNodeList children = parentElem.childNodes();
 
292
  for ( int i = 0; i < children.count(); ++i ) {
 
293
    const QDomElement childElem = children.at( i ).toElement();
 
294
    if ( childElem.isNull() || childElem.tagName() != Format::Tag::collection() )
 
295
      continue;
 
296
    Collection c = XmlReader::elementToCollection( childElem );
 
297
    c.setParentCollection( parentCollection );
 
298
    rv.append( c );
 
299
  }
 
300
 
 
301
  return rv;
 
302
}
 
303
 
 
304
 
 
305
Item::List XmlDocument::items(const Akonadi::Collection& collection, bool includePayload) const
 
306
{
 
307
  const QDomElement colElem = collectionElement( collection );
 
308
  if ( colElem.isNull() ) {
 
309
    d->lastError = i18n( "Unable to find collection %1", collection.name() );
 
310
    return Item::List();
 
311
  } else {
 
312
    d->lastError.clear();
 
313
  }
 
314
 
 
315
  Item::List items;
 
316
  const QDomNodeList children = colElem.childNodes();
 
317
  for ( int i = 0; i < children.count(); ++i ) {
 
318
    const QDomElement itemElem = children.at( i ).toElement();
 
319
    if ( itemElem.isNull() || itemElem.tagName() != Format::Tag::item() )
 
320
      continue;
 
321
    items += XmlReader::elementToItem( itemElem, includePayload );
 
322
  }
 
323
 
 
324
  return items;
 
325
}