tests/auto/xmlpatternsxqts/lib/XMLWriter.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QCoreApplication>
       
    43 #include <QDateTime>
       
    44 #include <QIODevice>
       
    45 #include <QList>
       
    46 #include <QPair>
       
    47 #include <QStack>
       
    48 #include <QtDebug>
       
    49 
       
    50 #include "XMLWriter.h"
       
    51 
       
    52 /* Issues:
       
    53  * - Switch to Qt's d-pointer semantics, if in Qt.
       
    54  * - Remove namespace(PatternistSDK), and change name, if in Qt.
       
    55  * - Is it really necessary to pass the tag name to endElement()?
       
    56  * - Could it be of interest to let the user control the encoding? Are those cases common
       
    57  *   enough to justify support in Qt? Using anything but UTF-8 or UTF-16
       
    58  *   means asking for trouble, from an interoperability perspective.
       
    59  */
       
    60 
       
    61 /* Design rationalis, comments:
       
    62  *
       
    63  * - The class is called XMLWriter to harvest familarity by being consistent with
       
    64  *   Java's XMLWriter class. If XMLWriter is moved to Qt, the name QXmlWriter is perhaps suitable.
       
    65  * - The class does not handle indentation because the "do one thing well"-principle is
       
    66  *   in use. XMLWriter should be fast and not assume a certain idea of indentation. Indentation
       
    67  *   should be implemented in a standalone QXmlContentHandler that performs the indentation and
       
    68  *   "has a" QXmlContentHandler which it in addition calls, and by that proxying/piping another
       
    69  *   QXmlContentHandler(which most likely is an XMLWriter). Thus, achieving a modularized,
       
    70  *   flexibly approach to indentation. A reason is also that indentation is very subjective.
       
    71  *   The indenter class should probably be called XMLIndenter/QXmlIndenter.
       
    72  * - It could be of interest to implement QXmlDTDHandler such that it would be possible to serialize
       
    73  *   DTDs. Must be done before BC becomes significant.
       
    74  * - I think the most valuable of this class is its Q_ASSERT tests. Many programmers have severe problems
       
    75  *   producing XML, and the tests helps them catching their mistakes. They therefore promote
       
    76  *   interoperability. Do not remove them. If any are wrong, fix them instead.
       
    77  */
       
    78 
       
    79 using namespace QPatternistSDK;
       
    80 
       
    81 /**
       
    82  * A namespace binding, prefix/namespace URI.
       
    83  */
       
    84 typedef QPair<QString, QString> NSBinding;
       
    85 typedef QList<NSBinding> NSBindingList;
       
    86 
       
    87 #ifdef QT_NO_DEBUG
       
    88 #   define DEBUG_CODE(code)
       
    89 #else
       
    90 #   define DEBUG_CODE(code) code
       
    91 #endif
       
    92 
       
    93 class XMLWriter::Private
       
    94 {
       
    95 public:
       
    96     inline Private(QIODevice *devP) : insideCDATA(false),
       
    97                                      addModificationNote(false),
       
    98                                      dev(devP)
       
    99     {
       
   100         hasContentStack.push(true);
       
   101     }
       
   102 
       
   103 #ifdef QT_NO_DEBUG
       
   104     inline void validateQName(const QString &) const
       
   105     {
       
   106     }
       
   107 
       
   108     inline void verifyNS(const QString &) const
       
   109     {
       
   110     }
       
   111 #else
       
   112     /**
       
   113      * Simple test of that @p name is an acceptable QName.
       
   114      */
       
   115     inline void validateQName(const QString &name)
       
   116     {
       
   117         Q_ASSERT_X(!name.isEmpty(), Q_FUNC_INFO,
       
   118                    "An XML name cannot be empty.");
       
   119         Q_ASSERT_X(!name.endsWith(QLatin1Char(':')), Q_FUNC_INFO,
       
   120                    "An XML name cannot end with a colon(QLatin1Char(':')).");
       
   121         Q_ASSERT_X(!name.contains(QRegExp(QLatin1String("[ \t\n]"))), Q_FUNC_INFO,
       
   122                    "An XML name cannot contain whitespace.");
       
   123     }
       
   124 
       
   125     /**
       
   126      * Ensures that the prefix of @p qName is declared.
       
   127      */
       
   128     inline void verifyNS(const QString &qName) const
       
   129     {
       
   130         const QString prefix(qName.left(qName.indexOf(QLatin1Char(':'))));
       
   131 
       
   132         if(qName.contains(QLatin1Char(':')) && prefix != QLatin1String("xml"))
       
   133         {
       
   134             bool foundPrefix = false;
       
   135             const QStack<NSBindingList>::const_iterator end(namespaceTracker.constEnd());
       
   136             QStack<NSBindingList>::const_iterator it(namespaceTracker.constBegin());
       
   137 
       
   138             for(; it != end; ++it)
       
   139             {
       
   140                 const NSBindingList::const_iterator lend((*it).constEnd());
       
   141                 NSBindingList::const_iterator lit((*it).constBegin());
       
   142 
       
   143                 for(; lit != lend; ++it)
       
   144                 {
       
   145                     if((*lit).first == prefix)
       
   146                     {
       
   147                         foundPrefix = true;
       
   148                         break;
       
   149                     }
       
   150                 }
       
   151                 if(foundPrefix)
       
   152                     break;
       
   153             }
       
   154 
       
   155             Q_ASSERT_X(foundPrefix, "XMLWriter::startElement()",
       
   156                        qPrintable(QString::fromLatin1("The prefix %1 is not declared. All prefixes "
       
   157                                           "except 'xml' must be declared.").arg(prefix)));
       
   158         }
       
   159     }
       
   160 #endif
       
   161 
       
   162     inline QString escapeElementContent(const QString &ch)
       
   163     {
       
   164         const int l = ch.length();
       
   165         QString retval;
       
   166 
       
   167         for(int i = 0; i != l; ++i)
       
   168         {
       
   169             const QChar c(ch.at(i));
       
   170 
       
   171             if(c == QLatin1Char(QLatin1Char('&')))
       
   172                 retval += QLatin1String("&amp;");
       
   173             else if(c == QLatin1Char(QLatin1Char('<')))
       
   174                 retval += QLatin1String("&lt;");
       
   175             else
       
   176                 retval += c;
       
   177         }
       
   178 
       
   179         return retval;
       
   180     }
       
   181 
       
   182     inline QString escapeAttributeContent(const QString &ch)
       
   183     {
       
   184         const int l = ch.length();
       
   185         QString retval;
       
   186 
       
   187         for(int i = 0; i != l; ++i)
       
   188         {
       
   189             const QChar c(ch.at(i));
       
   190 
       
   191             /* We don't have to escape '\'' because we use '\"' as attribute delimiter. */
       
   192             if(c == QLatin1Char('&'))
       
   193                 retval += QLatin1String("&amp;");
       
   194             else if(c == QLatin1Char('<'))
       
   195                 retval += QLatin1String("&lt;");
       
   196             else if(c == QLatin1Char('"'))
       
   197                 retval += QLatin1String("&quot;");
       
   198             else
       
   199                 retval += c;
       
   200         }
       
   201 
       
   202         return retval;
       
   203     }
       
   204 
       
   205     inline QString escapeCDATAContent(const QString &ch)
       
   206     {
       
   207         const int l = ch.length();
       
   208         QString retval;
       
   209         qint8 atEnd = 0;
       
   210 
       
   211         for(int i = 0; i != l; ++i)
       
   212         {
       
   213             const QChar c(ch.at(i));
       
   214 
       
   215             /* Escape '>' if in "]]>" */
       
   216             if(c == QLatin1Char(']'))
       
   217             {
       
   218                 if(atEnd == 0 || atEnd == 1)
       
   219                     ++atEnd;
       
   220                 else
       
   221                     atEnd = 0;
       
   222 
       
   223                 retval += QLatin1Char(']');
       
   224             }
       
   225             else if(c == QLatin1Char('>'))
       
   226             {
       
   227                 if(atEnd == 2)
       
   228                     retval += QLatin1String("&gt;");
       
   229                 else
       
   230                 {
       
   231                     atEnd = 0;
       
   232                     retval += QLatin1Char('>');
       
   233                 }
       
   234             }
       
   235             else
       
   236                 retval += c;
       
   237         }
       
   238 
       
   239         return retval;
       
   240     }
       
   241 
       
   242     /**
       
   243      * We wrap dev in this function such that we can deploy the Q_ASSERT_X
       
   244      * macro in each place it's used.
       
   245      */
       
   246     inline QIODevice *device() const
       
   247     {
       
   248         Q_ASSERT_X(dev, Q_FUNC_INFO,
       
   249                    "No device specified for XMLWriter; one must be specified with "
       
   250                    "setDevice() or via the constructor before XMLWriter can be used.");
       
   251         return dev;
       
   252     }
       
   253 
       
   254     /**
       
   255      * @returns true on success, otherwise false
       
   256      */
       
   257     inline bool serialize(const QString &data)
       
   258     {
       
   259         const QByteArray utf8(data.toUtf8());
       
   260 
       
   261         return device()->write(utf8) == utf8.size();
       
   262     }
       
   263 
       
   264     /**
       
   265      * @returns true on success, otherwise false
       
   266      */
       
   267     inline bool serialize(const char data)
       
   268     {
       
   269         return device()->putChar(data);
       
   270     }
       
   271 
       
   272     /**
       
   273      * @returns true on success, otherwise false
       
   274      */
       
   275     inline bool serialize(const char *data)
       
   276     {
       
   277         return device()->write(data) == qstrlen(data);
       
   278     }
       
   279 
       
   280     inline bool hasElementContent() const
       
   281     {
       
   282         return hasContentStack.top();
       
   283     }
       
   284 
       
   285     inline void handleElement()
       
   286     {
       
   287         if(!hasElementContent())
       
   288             serialize('>');
       
   289 
       
   290         /* This element is content for the parent. */
       
   291         hasContentStack.top() = true;
       
   292     }
       
   293 
       
   294     NSBindingList namespaces;
       
   295     bool insideCDATA;
       
   296     bool addModificationNote;
       
   297     QString msg;
       
   298     QIODevice *dev;
       
   299     QStack<bool> hasContentStack;
       
   300     QString errorString;
       
   301     DEBUG_CODE(QStack<QString> tags;)
       
   302     DEBUG_CODE(QStack<NSBindingList> namespaceTracker;)
       
   303 };
       
   304 
       
   305 /**
       
   306  * Reduces complexity. The empty else clause is for avoiding mess when macro
       
   307  * is used in the 'then' branch of an if clause, which is followed by an else clause.
       
   308  */
       
   309 #define serialize(string) if(!d->serialize(string)) \
       
   310                           { \
       
   311                               d->errorString = d->device()->errorString(); \
       
   312                               return false; \
       
   313                           } \
       
   314                           else do {} while (false)
       
   315 
       
   316 XMLWriter::XMLWriter(QIODevice *outStream) : d(new Private(outStream))
       
   317 {
       
   318 }
       
   319 
       
   320 XMLWriter::~XMLWriter()
       
   321 {
       
   322     delete d;
       
   323 }
       
   324 
       
   325 bool XMLWriter::startDocument()
       
   326 {
       
   327     if(!device()->isOpen() && !device()->open(QIODevice::WriteOnly))
       
   328         return false;
       
   329 
       
   330     if(d->addModificationNote)
       
   331     {
       
   332         if(d->msg.isNull())
       
   333         {
       
   334             d->msg = QString::fromLatin1("NOTE: This file was automatically generated "
       
   335                                          "by %1 at %2. All changes to this file will be lost.")
       
   336                                          .arg(QCoreApplication::instance()->applicationName(),
       
   337                                               QDateTime::currentDateTime().toString());
       
   338         }
       
   339         if(!comment(d->msg))
       
   340             return false;
       
   341 
       
   342         serialize('\n');
       
   343     }
       
   344 
       
   345     serialize(QLatin1String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"));
       
   346 
       
   347     return true;
       
   348 }
       
   349 
       
   350 bool XMLWriter::startElement(const QString &/*namespaceURI*/,
       
   351                              const QString &/*localName*/,
       
   352                              const QString &qName,
       
   353                              const QXmlAttributes &atts)
       
   354 {
       
   355     return startElement(qName, atts);
       
   356 }
       
   357 
       
   358 bool XMLWriter::startElement(const QString &qName,
       
   359                              const QXmlAttributes &atts)
       
   360 {
       
   361     Q_ASSERT_X(!d->insideCDATA, Q_FUNC_INFO,
       
   362                "Only characters() can be received when inside CDATA.");
       
   363     Q_ASSERT_X(!qName.startsWith(QLatin1String("xmlns")), Q_FUNC_INFO,
       
   364                "startElement should not be used for declaring prefixes, "
       
   365                "use startPrefixMapping() for that.");
       
   366 
       
   367     d->validateQName(qName);
       
   368     d->verifyNS(qName);
       
   369 
       
   370     d->handleElement();
       
   371 
       
   372     serialize('<');
       
   373     serialize(qName);
       
   374 
       
   375     DEBUG_CODE(d->tags.push(qName));
       
   376     DEBUG_CODE(d->namespaceTracker.push(d->namespaces));
       
   377 
       
   378     /* Add namespace declarations. */
       
   379     const NSBindingList::const_iterator end(d->namespaces.constEnd());
       
   380     NSBindingList::const_iterator it(d->namespaces.constBegin());
       
   381 
       
   382     for(; it != end; ++it)
       
   383     {
       
   384         if((*it).first.isEmpty())
       
   385             serialize(" xmlns=");
       
   386         else
       
   387         {
       
   388             serialize(" xmlns:");
       
   389             serialize((*it).first);
       
   390             serialize('=');
       
   391         }
       
   392 
       
   393         serialize('"');
       
   394         serialize(d->escapeElementContent((*it).second));
       
   395         serialize('"');
       
   396     }
       
   397     d->namespaces.clear();
       
   398 
       
   399     const int c = atts.count();
       
   400 
       
   401     /* Serialize attributes. */
       
   402     for(int i = 0; i != c; ++i)
       
   403     {
       
   404         d->validateQName(atts.qName(i));
       
   405         d->verifyNS(atts.qName(i));
       
   406 
       
   407         serialize(' ');
       
   408         serialize(atts.qName(i));
       
   409         serialize("=\"");
       
   410         serialize(d->escapeAttributeContent(atts.value(i)));
       
   411         serialize('"');
       
   412     }
       
   413 
       
   414     d->hasContentStack.push(false);
       
   415     return true;
       
   416 }
       
   417 
       
   418 bool XMLWriter::endElement(const QString &/*namespaceURI*/,
       
   419                            const QString &/*localName*/,
       
   420                            const QString &qName)
       
   421 {
       
   422     return endElement(qName);
       
   423 }
       
   424 
       
   425 bool XMLWriter::endElement(const QString &qName)
       
   426 {
       
   427     Q_ASSERT_X(!d->insideCDATA, Q_FUNC_INFO,
       
   428                "Only characters() can be received when inside CDATA.");
       
   429     Q_ASSERT_X(d->tags.pop() == qName, Q_FUNC_INFO,
       
   430                "The element tags are not balanced, the produced XML is invalid.");
       
   431 
       
   432     DEBUG_CODE(d->namespaceTracker.pop());
       
   433 
       
   434     /* "this" element is content for our parent, so ensure hasElementContent is true. */
       
   435 
       
   436     if(d->hasElementContent())
       
   437     {
       
   438         serialize(QLatin1String("</"));
       
   439         serialize(qName);
       
   440         serialize('>');
       
   441     }
       
   442     else
       
   443         serialize(QLatin1String("/>"));
       
   444 
       
   445     d->hasContentStack.pop();
       
   446 
       
   447     return true;
       
   448 }
       
   449 
       
   450 bool XMLWriter::startPrefixMapping(const QString &prefix, const QString &uri)
       
   451 {
       
   452     Q_ASSERT_X(!d->insideCDATA, Q_FUNC_INFO,
       
   453                "Only characters() can be received when inside CDATA.");
       
   454     Q_ASSERT_X(prefix.toLower() != QLatin1String("xml") ||
       
   455                (prefix.toLower() == QLatin1String("xml") &&
       
   456                (uri == QLatin1String("http://www.w3.org/TR/REC-xml-names/") ||
       
   457                                               uri.isEmpty())),
       
   458                Q_FUNC_INFO,
       
   459                "The prefix 'xml' can only be bound to the namespace "
       
   460                "\"http://www.w3.org/TR/REC-xml-names/\".");
       
   461     Q_ASSERT_X(prefix.toLower() != QLatin1String("xml") &&
       
   462                 uri != QLatin1String("http://www.w3.org/TR/REC-xml-names/"),
       
   463                Q_FUNC_INFO,
       
   464                "The namespace \"http://www.w3.org/TR/REC-xml-names/\" can only be bound to the "
       
   465                "\"xml\" prefix.");
       
   466 
       
   467     d->namespaces.append(qMakePair(prefix, uri));
       
   468     return true;
       
   469 }
       
   470 
       
   471 bool XMLWriter::processingInstruction(const QString &target,
       
   472                                       const QString &data)
       
   473 {
       
   474     Q_ASSERT_X(target.toLower() != QLatin1String("xml"), Q_FUNC_INFO,
       
   475                "A processing instruction cannot have the name xml in any "
       
   476                "capitalization, because it is reserved.");
       
   477     Q_ASSERT_X(!data.contains(QLatin1String("?>")), Q_FUNC_INFO,
       
   478                "The content of a processing instruction cannot contain the string \"?>\".");
       
   479     Q_ASSERT_X(!d->insideCDATA, "XMLWriter::processingInstruction()",
       
   480                "Only characters() can be received when inside CDATA.");
       
   481 
       
   482     d->handleElement();
       
   483 
       
   484     serialize(QLatin1String("<?"));
       
   485     serialize(target);
       
   486     serialize(' ');
       
   487     serialize(data);
       
   488     serialize(QLatin1String("?>"));
       
   489     return true;
       
   490 }
       
   491 
       
   492 bool XMLWriter::characters(const QString &ch)
       
   493 {
       
   494     Q_ASSERT_X(d->tags.count() >= 1, Q_FUNC_INFO,
       
   495                "Text nodes can only appear inside elements(no elements sent).");
       
   496     d->handleElement();
       
   497 
       
   498     if(d->insideCDATA)
       
   499         serialize(d->escapeCDATAContent(ch));
       
   500     else
       
   501         serialize(d->escapeElementContent(ch));
       
   502 
       
   503     return true;
       
   504 }
       
   505 
       
   506 bool XMLWriter::comment(const QString &ch)
       
   507 {
       
   508     Q_ASSERT_X(!d->insideCDATA, Q_FUNC_INFO,
       
   509                "Only characters() can be received when inside CDATA.");
       
   510     Q_ASSERT_X(!ch.contains(QLatin1String("--")), Q_FUNC_INFO,
       
   511                "XML comments may not contain double-hyphens(\"--\").");
       
   512     Q_ASSERT_X(!ch.endsWith(QLatin1Char('-')), Q_FUNC_INFO,
       
   513                "XML comments cannot end with a hyphen, \"-\"(add a space, for example).");
       
   514     /* A comment starting with "<!---" is ok. */
       
   515 
       
   516     d->handleElement();
       
   517 
       
   518     serialize(QLatin1String("<!--"));
       
   519     serialize(ch);
       
   520     serialize(QLatin1String("-->"));
       
   521 
       
   522     return true;
       
   523 }
       
   524 
       
   525 bool XMLWriter::startCDATA()
       
   526 {
       
   527     Q_ASSERT_X(d->insideCDATA, Q_FUNC_INFO,
       
   528                "startCDATA() has already been called.");
       
   529     Q_ASSERT_X(d->tags.count() >= 1, Q_FUNC_INFO,
       
   530                "CDATA sections can only appear inside elements(no elements sent).");
       
   531     d->insideCDATA = true;
       
   532     serialize(QLatin1String("<![CDATA["));
       
   533     return true;
       
   534 }
       
   535 
       
   536 bool XMLWriter::endCDATA()
       
   537 {
       
   538     d->insideCDATA = false;
       
   539     serialize("]]>");
       
   540     return true;
       
   541 }
       
   542 
       
   543 bool XMLWriter::startDTD(const QString &name,
       
   544                          const QString &publicId,
       
   545                          const QString &systemId)
       
   546 {
       
   547     Q_ASSERT_X(!d->insideCDATA, Q_FUNC_INFO,
       
   548                "Only characters() can be received when inside CDATA.");
       
   549     Q_ASSERT_X(!name.isEmpty(), Q_FUNC_INFO,
       
   550                "The DOCTYPE name cannot be empty.");
       
   551     Q_ASSERT_X(d->tags.isEmpty() && d->namespaces.isEmpty(), Q_FUNC_INFO,
       
   552                "No content such as namespace declarations or elements can be serialized "
       
   553                "before the DOCTYPE declaration, the XML is invalid.");
       
   554     Q_ASSERT_X(!publicId.contains(QLatin1Char('"')), Q_FUNC_INFO,
       
   555                "The PUBLIC ID cannot contain quotes('\"').");
       
   556     Q_ASSERT_X(!systemId.contains(QLatin1Char('"')), Q_FUNC_INFO,
       
   557                "The SYSTEM ID cannot contain quotes('\"').");
       
   558 
       
   559     serialize(QLatin1String("<!DOCTYPE "));
       
   560     serialize(name);
       
   561 
       
   562     if(!publicId.isEmpty())
       
   563     {
       
   564         Q_ASSERT_X(!systemId.isEmpty(), Q_FUNC_INFO,
       
   565                    "When a public identifier is specified, a system identifier "
       
   566                    "must also be specified in order to produce valid XML.");
       
   567         serialize(" PUBLIC \"");
       
   568         serialize(publicId);
       
   569         serialize('"');
       
   570     }
       
   571 
       
   572     if(!systemId.isEmpty())
       
   573     {
       
   574         if(publicId.isEmpty())
       
   575             serialize(" SYSTEM");
       
   576 
       
   577         serialize(" \"");
       
   578         serialize(systemId);
       
   579         serialize('"');
       
   580     }
       
   581 
       
   582     return true;
       
   583 }
       
   584 
       
   585 bool XMLWriter::endDTD()
       
   586 {
       
   587     Q_ASSERT_X(d->tags.isEmpty() && d->namespaces.isEmpty(), Q_FUNC_INFO,
       
   588                "Content such as namespace declarations or elements cannot occur inside "
       
   589                "the DOCTYPE declaration, the XML is invalid.");
       
   590     serialize(QLatin1String(">\n"));
       
   591     return true;
       
   592 }
       
   593 
       
   594 bool XMLWriter::startEntity(const QString &)
       
   595 {
       
   596     return true;
       
   597 }
       
   598 
       
   599 bool XMLWriter::endEntity(const QString &)
       
   600 {
       
   601     return true;
       
   602 }
       
   603 
       
   604 void XMLWriter::setMessage(const QString &msg)
       
   605 {
       
   606     d->msg = msg;
       
   607 }
       
   608 
       
   609 QString XMLWriter::modificationMessage() const
       
   610 {
       
   611     return d->msg;
       
   612 }
       
   613 
       
   614 bool XMLWriter::endDocument()
       
   615 {
       
   616     Q_ASSERT_X(d->tags.isEmpty(), Q_FUNC_INFO,
       
   617                "endDocument() called before all elements were closed with endElement().");
       
   618     d->device()->close();
       
   619     return true;
       
   620 }
       
   621 
       
   622 QString XMLWriter::errorString() const
       
   623 {
       
   624     return d->errorString;
       
   625 }
       
   626 
       
   627 bool XMLWriter::ignorableWhitespace(const QString &ch)
       
   628 {
       
   629     return characters(ch);
       
   630 }
       
   631 
       
   632 bool XMLWriter::endPrefixMapping(const QString &)
       
   633 {
       
   634     /* Again, should we do something with this? */
       
   635     return true;
       
   636 }
       
   637 
       
   638 bool XMLWriter::skippedEntity(const QString &)
       
   639 {
       
   640     return true;
       
   641 }
       
   642 
       
   643 void XMLWriter::setDocumentLocator(QXmlLocator *)
       
   644 {
       
   645 }
       
   646 
       
   647 QIODevice *XMLWriter::device() const
       
   648 {
       
   649     return d->dev;
       
   650 }
       
   651 
       
   652 void XMLWriter::setDevice(QIODevice *dev)
       
   653 {
       
   654     d->dev = dev;
       
   655 }
       
   656 
       
   657 void XMLWriter::setAddMessage(const bool toggle)
       
   658 {
       
   659     d->addModificationNote = toggle;
       
   660 }
       
   661 
       
   662 bool XMLWriter::addModificationMessage() const
       
   663 {
       
   664     return d->addModificationNote;
       
   665 }
       
   666 
       
   667 #undef serialize
       
   668 // vim: et:ts=4:sw=4:sts=4
       
   669