File indexing completed on 2024-05-12 16:29:18

0001 /* This file is part of the KDE project
0002 
0003    Copyright (C) 2013 Inge Wallin <inge@lysator.liu.se>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019 */
0020 
0021 
0022 // Own
0023 #include "KoXmlStreamReader.h"
0024 
0025 // Qt
0026 #include <QString>
0027 #include <QStringList>
0028 #include <QSet>
0029 
0030 #include "Odf2Debug.h"
0031 
0032 
0033 // ================================================================
0034 //             class KoXmlStreamReader and Private class
0035 
0036 
0037 class Q_DECL_HIDDEN KoXmlStreamReader::Private
0038 {
0039 public:
0040     Private(KoXmlStreamReader *qq);
0041     ~Private();
0042 
0043     void clear();
0044 
0045     // Checks the soundness of the whole document.  Must be called
0046     // after the namespace declarations are read.
0047     void        checkSoundness();
0048 
0049     // Builds a prefix for the current element. Only called if the
0050     // document is unsound.
0051     QStringRef buildNewPrefix();
0052     // Builds a qualified name for the current element. Only called if
0053     // the document is unsound.
0054     QStringRef  buildQName();
0055 
0056     KoXmlStreamReader *q;       // The owner object;
0057 
0058     bool  isSound;              // True if the document is sound (see the class doc for details)
0059     bool  isChecked;            // True if the soundness is checked
0060 
0061     // These are filled using the addEx{pected,tra}Namespace() functions.
0062     QHash<QString, QString>  expectedNamespaces;  // nsUri, prefix
0063     QHash<QString, QString>  extraNamespaces;     // nsUri, prefix
0064 
0065     // This is only used when a document is unsound, but is always created.
0066     QHash<QString, QString>  prefixes; // nsUri, prefix
0067 
0068     // If the document is unsound, we need to build the prefix and
0069     // qualified names from a prefix that we get from "prefixes" and
0070     // the actual name.  But we return a QStringRef and not QString so
0071     // we need to make sure that the stringref is valid until this
0072     // KoXmlStreamReader is destructed.  So we use this QSet as a
0073     // cache of all constructed qualified names that we ever generate.
0074     QSet<QString>  prefixCache;
0075     QSet<QString>  qualifiedNamesCache;
0076 };
0077 
0078 
0079 KoXmlStreamReader::Private::Private(KoXmlStreamReader *qq)
0080     : q(qq)
0081 {
0082     clear();
0083 }
0084 
0085 KoXmlStreamReader::Private::~Private()
0086 {
0087 }
0088 
0089 
0090 void KoXmlStreamReader::Private::clear()
0091 {
0092     // The initial state is Unsound and Unchecked.  The check may
0093     // switch it to Sound.  See the class documentation for an
0094     // explanation of those terms.
0095     isSound = false;
0096     isChecked = false;
0097 
0098     expectedNamespaces.clear();
0099     extraNamespaces.clear();
0100 
0101     prefixes.clear();
0102     prefixCache.clear();
0103     qualifiedNamesCache.clear();
0104 }
0105 
0106 
0107 void KoXmlStreamReader::Private::checkSoundness()
0108 {
0109     isSound = true;
0110 
0111     // Temp values
0112     QStringList    namespacesToFix;    // List of namespaces we need to create a unique prefix for
0113     QSet<QString>  usedPrefixes;
0114 
0115     // Initialize by setting all expected prefixes and all extra ones.
0116     prefixes.clear();
0117     foreach(const QString &nsUri, expectedNamespaces.keys()) {
0118         QString prefix = expectedNamespaces.value(nsUri);
0119 
0120         prefixes.insert(nsUri, prefix);
0121         usedPrefixes.insert(prefix);
0122     }
0123     foreach(const QString &nsUri, extraNamespaces.keys()) {
0124         QString prefix = extraNamespaces.value(nsUri);
0125 
0126         prefixes.insert(nsUri, prefix);
0127         usedPrefixes.insert(prefix);
0128     }
0129 
0130     // The document is "Sound" if for all the declared namespaces in
0131     // the document, the prefix is the same as the one in the expected
0132     // namespaces for the same namespace URI.
0133     //
0134     // If it is not Sound, then we need to rewrite the prefixes for
0135     // the qualified names when the caller wants to access them.
0136     // Hopefully this only happens once in a million documents (and it
0137     // would be interesting to know which application created such a
0138     // strange beast).
0139     //
0140     QXmlStreamNamespaceDeclarations  nsDeclarations = q->QXmlStreamReader::namespaceDeclarations();
0141     foreach(const QXmlStreamNamespaceDeclaration &decl, nsDeclarations) {
0142 
0143         QString nsUri(decl.namespaceUri().toString());
0144         QString prefix(decl.prefix().toString());
0145 
0146         if (prefixes.contains(nsUri)) {
0147             if (prefix == prefixes.value(nsUri)) {
0148 
0149                 // 1. nsUri = expected nsUri AND prefix = expected prefix:
0150                 //
0151                 // Soundness is not disturbed. Let's continue with the next declaration.
0152                 continue;
0153             }
0154             else {
0155                 // 2. nsUri = expected nsUri AND prefix != expected prefix:
0156                 //
0157                 // Document is not sound but we don't need to do
0158                 // anything else; the expected prefix is already in
0159                 // prefixes[] and the prefix will be rewritten to the
0160                 // expected one when used later in the document.
0161                 isSound = false;
0162                 continue;
0163             }
0164         }
0165         else {
0166             // 3. nsUri is not among the expected nsUri's
0167             //
0168             // Let's check if the prefix is unique or if it already
0169             // exists among the expected ones.  If it is unique the
0170             // soundness is not affected, otherwise it is unsound.
0171             if (usedPrefixes.contains(prefix)) {
0172 
0173                 // Yes, the prefix is used for another namespace among
0174                 // the expected ones.  Let's store this namespace for
0175                 // now and create a unique, non-"expected" prefix
0176                 // later when all namespaces and prefixes are known.
0177                 isSound = false;
0178                 namespacesToFix.append(nsUri);
0179             }
0180             else {
0181                 prefixes.insert(nsUri, prefix);
0182                 usedPrefixes.insert(prefix);
0183             }
0184         }
0185     }
0186 
0187     //debugOdf2 << "namespaces to fix:" << namespacesToFix;
0188 
0189     // Finally, if necessary, create unique prefixes for namespaces
0190     // that are found to use one of the expected prefixes.  It doesn't
0191     // much matter what we come up with here since these will have to
0192     // be accessed through namespaceUri() anyway.
0193     int number = 1;
0194     foreach (const QString &ns, namespacesToFix) {
0195         bool ok = false;
0196         QString pfx;
0197         while (!ok) {
0198             pfx = QString("pfx%1").arg(number++);
0199             if (!usedPrefixes.contains(pfx)) {
0200                 ok = true;
0201             }
0202         }
0203         prefixes.insert(ns, pfx);
0204     }
0205 
0206     //debugOdf2 << "Document soundness:" << isSound;
0207     //debugOdf2 << "prefixes:" << prefixes;
0208 
0209     isChecked = true;
0210 }
0211 
0212 QStringRef KoXmlStreamReader::Private::buildNewPrefix()
0213 {
0214     if (!isChecked) {
0215         checkSoundness();       // Sets isChecked and isSound;
0216     }
0217 
0218     if (isSound) {
0219         return q->prefix();
0220     }
0221 
0222     // FIXME: Handle undeclared prefixes.  (Is that even legal?)
0223     //QString nsUri = q->QXmlStreamReader::namespaceUri().toString();
0224     QString newPrefix = prefixes.value(q->QXmlStreamReader::namespaceUri().toString());
0225 
0226     // The following code is because prefix() returns a QStringRef,
0227     // not a QString.  So we need to make sure that the QString that
0228     // it references stays valid until the end of the document is
0229     // parsed.  We do this by storing all prefix names that are
0230     // accessed in a QSet<QString> and return a QStringRef that
0231     // references the copy in the set.  Ugly but effective.
0232 #if 1
0233     if (!prefixCache.contains(newPrefix)) {
0234         // FIXME: Is there a way to do this at the same time as the
0235         // check without creating a double copy if it was already inserted?
0236         prefixCache.insert(newPrefix);
0237     }
0238 
0239     QSet<QString>::ConstIterator  it = prefixCache.find(newPrefix);
0240 #else
0241     // This should work too but it's unclear from the documentation
0242     // what is returned if it was already in the set.  It only
0243     // mentions "the inserted item"
0244     QSet<QString>::ConstIterator  it = prefixCace.insert(newPrefix);
0245 #endif
0246 
0247     // Will always succeed since we entered it if it didn't exist already.
0248     return (*it).leftRef(-1);
0249 }
0250 
0251 QStringRef KoXmlStreamReader::Private::buildQName()
0252 {
0253     if (!isChecked) {
0254         checkSoundness();       // Sets isChecked and isSound;
0255     }
0256 
0257     if (isSound) {
0258         return q->qualifiedName();
0259     }
0260 
0261     // FIXME: Handle undeclared prefixes.  (Is that even legal?)
0262     //QString nsUri = q->QXmlStreamReader::namespaceUri().toString();
0263     QString qualifiedName = prefixes.value(q->QXmlStreamReader::namespaceUri().toString())
0264         + ':' + q->QXmlStreamReader::name().toString();
0265 
0266     // The following code is because qualifiedName() returns a
0267     // QStringRef, not a QString.  So we need to make sure that the
0268     // QString that it references stays valid until the end of the
0269     // document is parsed.  We do this by storing all qualified names
0270     // that are accessed in a QSet<QString> and return a QStringRef
0271     // that references the copy in the set.  Ugly but effective.
0272 #if 1
0273     if (!qualifiedNamesCache.contains(qualifiedName)) {
0274         // FIXME: Is there a way to do this at the same time as the
0275         // check without creating a double copy if it was already inserted?
0276         qualifiedNamesCache.insert(qualifiedName);
0277     }
0278 
0279     QSet<QString>::ConstIterator  it = qualifiedNamesCache.find(qualifiedName);
0280 #else
0281     // This should work too but it's unclear from the documentation
0282     // what is returned if it was already in the set.  It only
0283     // mentions "the inserted item"
0284     QSet<QString>::ConstIterator  it = qualifiedNamesCache.insert(qualifiedName);
0285 #endif
0286 
0287     // Will always succeed since we entered it if it didn't exist already.
0288     return (*it).leftRef(-1);
0289 }
0290 
0291 
0292 // ----------------------------------------------------------------
0293 //                     class KoXmlStreamReader
0294 
0295 
0296 KoXmlStreamReader::KoXmlStreamReader()
0297     : QXmlStreamReader()
0298     , d(new KoXmlStreamReader::Private(this))
0299 {
0300 }
0301 
0302 KoXmlStreamReader::KoXmlStreamReader(QIODevice *device)
0303     : QXmlStreamReader(device)
0304     , d(new KoXmlStreamReader::Private(this))
0305 {
0306 }
0307 
0308 KoXmlStreamReader::KoXmlStreamReader(const QByteArray &data)
0309     : QXmlStreamReader(data)
0310     , d(new KoXmlStreamReader::Private(this))
0311 {
0312 }
0313 
0314 KoXmlStreamReader::KoXmlStreamReader(const QString &data)
0315     : QXmlStreamReader(data)
0316     , d(new KoXmlStreamReader::Private(this))
0317 {
0318 }
0319 
0320 KoXmlStreamReader::KoXmlStreamReader(const char *data)
0321     : QXmlStreamReader(data)
0322     , d(new KoXmlStreamReader::Private(this))
0323 {
0324 }
0325 
0326 KoXmlStreamReader::~KoXmlStreamReader()
0327 {
0328     delete d;
0329 }
0330 
0331 
0332 void KoXmlStreamReader::clear()
0333 {
0334     d->clear();
0335 
0336     QXmlStreamReader::clear();
0337 }
0338 
0339 
0340 void KoXmlStreamReader::addExpectedNamespace(const QString &prefix, const QString &namespaceUri)
0341 {
0342     d->expectedNamespaces.insert(namespaceUri, prefix);
0343 
0344     d->isChecked = false;
0345     d->isSound = false;
0346 }
0347 
0348 void KoXmlStreamReader::addExtraNamespace(const QString &prefix, const QString &namespaceUri)
0349 {
0350     d->extraNamespaces.insert(namespaceUri, prefix);
0351 
0352     d->isChecked = false;
0353     d->isSound = false;
0354 }
0355 
0356 
0357 // ----------------------------------------------------------------
0358 //                 Reimplemented from QXmlStreamReader
0359 
0360 
0361 // Should these be made inline?  that would make it very fast at the
0362 // cost of a possibly unstable API.
0363 
0364 QStringRef KoXmlStreamReader::prefix() const
0365 {
0366     return d->isSound ? QXmlStreamReader::prefix() : d->buildNewPrefix();
0367 }
0368 
0369 QStringRef KoXmlStreamReader::qualifiedName() const
0370 {
0371     return d->isSound ? QXmlStreamReader::qualifiedName() : d->buildQName();
0372 }
0373 
0374 
0375 void KoXmlStreamReader::setDevice(QIODevice *device)
0376 {
0377     // Setting the device clears the checked status since we don't know
0378     // which namespace declarations that will be in the new document.
0379     d->isChecked = false;
0380     d->isSound = false;
0381 
0382     QXmlStreamReader::setDevice(device);
0383 }
0384 
0385 KoXmlStreamAttributes KoXmlStreamReader::attributes() const
0386 {
0387     QXmlStreamAttributes   qAttrs = QXmlStreamReader::attributes();
0388     KoXmlStreamAttributes  retval = KoXmlStreamAttributes(this, qAttrs);
0389 
0390     return retval;
0391 }
0392 
0393 
0394 // ----------------------------------------------------------------
0395 //                         private functions
0396 
0397 
0398 bool KoXmlStreamReader::isSound() const
0399 {
0400     return d->isSound;
0401 }
0402 
0403 
0404 // ================================================================
0405 //             class KoXmlStreamAttribute and Private class
0406 
0407 
0408 class Q_DECL_HIDDEN KoXmlStreamAttribute::Private
0409 {
0410 public:
0411     Private(const QXmlStreamAttribute *attr, const KoXmlStreamReader *r);
0412     Private(const KoXmlStreamAttribute::Private &other);
0413     ~Private();
0414 
0415     void generateQName();
0416 
0417     const QXmlStreamAttribute *qAttr;
0418     const KoXmlStreamReader   *reader;
0419 
0420     // These two are only used when the document is unsound
0421     QString  qName;             // qualifiedName if it was ever asked for.
0422     int      prefixLen;         // the length of the prefix alone. -1 means uninitialized.
0423 };
0424 
0425 KoXmlStreamAttribute::Private::Private(const QXmlStreamAttribute *attr, const KoXmlStreamReader *r)
0426     : qAttr(attr)
0427     , reader(r)
0428     , qName()
0429     , prefixLen(-1)
0430 {
0431 }
0432 
0433 KoXmlStreamAttribute::Private::Private(const KoXmlStreamAttribute::Private &other)
0434     : qAttr(other.qAttr)
0435     , reader(other.reader)
0436     , qName(other.qName)
0437     , prefixLen(other.prefixLen)
0438 {
0439 }
0440 
0441 KoXmlStreamAttribute::Private::~Private()
0442 {
0443 }
0444 
0445 
0446 void KoXmlStreamAttribute::Private::generateQName()
0447 {
0448     qName = reader->d->prefixes.value(qAttr->namespaceUri().toString());
0449     prefixLen = qName.size();
0450 
0451     qName += QLatin1Char(':') + qAttr->name();
0452 }
0453 
0454 
0455 // ----------------------------------------------------------------
0456 
0457 
0458 
0459 KoXmlStreamAttribute::KoXmlStreamAttribute()
0460     : d(new KoXmlStreamAttribute::Private(0, 0))
0461 {
0462     //debugOdf2 << "default constructor called";
0463 }
0464 
0465 KoXmlStreamAttribute::KoXmlStreamAttribute(const QXmlStreamAttribute *attr,
0466                                            const KoXmlStreamReader *reader)
0467     : d(new KoXmlStreamAttribute::Private(attr, reader))
0468 {
0469     //debugOdf2 << "normal constructor called";
0470 }
0471 
0472 KoXmlStreamAttribute::KoXmlStreamAttribute(const KoXmlStreamAttribute &other)
0473     : d(new KoXmlStreamAttribute::Private(*other.d))
0474 {
0475     //debugOdf2 << "copy constructor called";
0476 }
0477 
0478 KoXmlStreamAttribute::~KoXmlStreamAttribute()
0479 {
0480     delete d;
0481 }
0482 
0483 
0484 bool KoXmlStreamAttribute::isDefault() const
0485 {
0486     return d->qAttr->isDefault();
0487 }
0488 
0489 QStringRef KoXmlStreamAttribute::name() const
0490 {
0491     return d->qAttr->name();
0492 }
0493 
0494 QStringRef KoXmlStreamAttribute::namespaceUri() const
0495 {
0496     return d->qAttr->namespaceUri();
0497 }
0498 
0499 
0500 QStringRef KoXmlStreamAttribute::prefix() const
0501 {
0502     if (d->reader->isSound()) {
0503         return d->qAttr->prefix();
0504     }
0505 
0506     if (d->prefixLen == -1) {
0507         d->generateQName();
0508     }
0509 
0510     return d->qName.leftRef(d->prefixLen);
0511 }
0512 
0513 
0514 QStringRef KoXmlStreamAttribute::qualifiedName() const
0515 {
0516     if (d->reader->isSound()) {
0517         return d->qAttr->qualifiedName();
0518     }
0519 
0520     if (d->prefixLen == -1) {
0521         d->generateQName();
0522     }
0523 
0524     return d->qName.leftRef(-1);
0525 }
0526 
0527 
0528 QStringRef KoXmlStreamAttribute::value() const
0529 {
0530     return d->qAttr->value();
0531 }
0532 
0533 
0534 bool KoXmlStreamAttribute::operator==(const KoXmlStreamAttribute &other) const
0535 {
0536     return d->qAttr == other.d->qAttr;
0537 }
0538 
0539 bool KoXmlStreamAttribute::operator!=(const KoXmlStreamAttribute &other) const
0540 {
0541     return d->qAttr != other.d->qAttr;
0542 }
0543 
0544 
0545 KoXmlStreamAttribute &KoXmlStreamAttribute::operator=(const KoXmlStreamAttribute &other)
0546 {
0547     d->qAttr = other.d->qAttr;
0548     d->reader = other.d->reader;
0549     d->qName = other.d->qName;
0550     d->prefixLen = other.d->prefixLen;
0551 
0552     return *this;
0553 }
0554 
0555 
0556 // ================================================================
0557 //             class KoXmlStreamAttributes and Private class
0558 
0559 
0560 class Q_DECL_HIDDEN KoXmlStreamAttributes::Private : public QSharedData
0561 {
0562 public:
0563     Private(const KoXmlStreamReader *r, const QXmlStreamAttributes &qa);
0564     ~Private();
0565 
0566     const KoXmlStreamReader      *reader;
0567     QVector<KoXmlStreamAttribute> koAttrs;
0568     const QXmlStreamAttributes    qAttrs; // We need the Q attributes to live while this class lives.
0569 };
0570 
0571 KoXmlStreamAttributes::Private::Private(const KoXmlStreamReader *r, const QXmlStreamAttributes &qa)
0572     : reader(r)
0573     , koAttrs(qa.size())
0574     , qAttrs(qa)
0575 {
0576 }
0577 
0578 KoXmlStreamAttributes::Private::~Private()
0579 {
0580 }
0581 
0582 
0583 // ----------------------------------------------------------------
0584 
0585 
0586 KoXmlStreamAttributes::KoXmlStreamAttributes(const KoXmlStreamReader *r,
0587                                              const QXmlStreamAttributes &qAttrs)
0588     : d(new KoXmlStreamAttributes::Private(r, qAttrs))
0589 {
0590     for (int i = 0; i < qAttrs.size(); ++i) {
0591         d->koAttrs[i] = KoXmlStreamAttribute(&qAttrs[i], d->reader);
0592     }
0593 }
0594 
0595 KoXmlStreamAttributes::KoXmlStreamAttributes(const KoXmlStreamAttributes &other)
0596     : d(other.d)
0597 {
0598 }
0599 
0600 KoXmlStreamAttributes::~KoXmlStreamAttributes()
0601 {
0602     // No delete because d is a QSharedDataPointer;
0603 }
0604 
0605 KoXmlStreamAttributes &KoXmlStreamAttributes::operator=(const KoXmlStreamAttributes &other)
0606 {
0607     d = other.d;
0608     return *this;
0609 }
0610 
0611 
0612 // Relevant parts of the QVector API
0613 const KoXmlStreamAttribute& KoXmlStreamAttributes::at(int i) const
0614 {
0615     return d->koAttrs[i];
0616 }
0617 
0618 int KoXmlStreamAttributes::size() const
0619 {
0620     return d->koAttrs.size();
0621 }
0622 
0623 KoXmlStreamAttribute KoXmlStreamAttributes::value(int i) const
0624 {
0625     return d->koAttrs.value(i);
0626 }
0627 
0628 const KoXmlStreamAttribute& KoXmlStreamAttributes::operator[](int i) const
0629 {
0630     return d->koAttrs[i];//.operator[](i);
0631 }
0632 
0633 KoXmlStreamAttributes::const_iterator KoXmlStreamAttributes::begin() const
0634 {
0635     return const_iterator(d->koAttrs.begin());
0636 }
0637 
0638 KoXmlStreamAttributes::const_iterator KoXmlStreamAttributes::end() const
0639 {
0640     return const_iterator(d->koAttrs.end());
0641 }
0642 
0643 
0644 // reimplemented from QXmlStreamAttributes
0645 bool KoXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const
0646 {
0647     for (int i = 0; i < size(); ++i) {
0648         // This compares with the expected name always.
0649         if (qualifiedName == this->at(i).qualifiedName()) {
0650             return true;
0651         }
0652     }
0653 
0654     return false;
0655 }
0656 
0657 
0658 bool KoXmlStreamAttributes::hasAttribute(const QLatin1String &qualifiedName) const
0659 {
0660 #if 1
0661     const QString qName(qualifiedName);
0662     return hasAttribute(qName);
0663 #else
0664     for (int i = 0; i < size(); ++i) {
0665         if (qualifiedName == this->at(i).qualifiedName()) {
0666             return true;
0667         }
0668     }
0669 
0670     return false;
0671 #endif
0672 }
0673 
0674 
0675 QStringRef KoXmlStreamAttributes::value(const QString &qualifiedName) const
0676 {
0677     for (int i = 0; i < size(); ++i) {
0678         if (qualifiedName == this->at(i).qualifiedName()) {
0679             return this->at(i).value();
0680         }
0681     }
0682 
0683     return QStringRef();
0684 }
0685 
0686 
0687 QStringRef KoXmlStreamAttributes::value(const QLatin1String &qualifiedName) const
0688 {
0689     // FIXME: Find faster way.
0690     const QString qName(qualifiedName);
0691     return value(qName);
0692 }
0693 
0694 
0695 // ================================================================
0696 //                         non-class functions
0697 
0698 
0699 void prepareForOdf(KoXmlStreamReader &reader)
0700 {
0701     // This list of namespaces is taken from KoXmlNs.cpp
0702     // Maybe not all of them are expected in an ODF document?
0703     reader.addExpectedNamespace("office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0");
0704     reader.addExpectedNamespace("meta", "urn:oasis:names:tc:opendocument:xmlns:meta:1.0");
0705     reader.addExpectedNamespace("config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0");
0706     reader.addExpectedNamespace("text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0");
0707     reader.addExpectedNamespace("table", "urn:oasis:names:tc:opendocument:xmlns:table:1.0");
0708     reader.addExpectedNamespace("draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
0709     reader.addExpectedNamespace("presentation", "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0");
0710     reader.addExpectedNamespace("dr3d", "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0");
0711     reader.addExpectedNamespace("chart", "urn:oasis:names:tc:opendocument:xmlns:chart:1.0");
0712     reader.addExpectedNamespace("form", "urn:oasis:names:tc:opendocument:xmlns:form:1.0");
0713     reader.addExpectedNamespace("script", "urn:oasis:names:tc:opendocument:xmlns:script:1.0");
0714     reader.addExpectedNamespace("style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0");
0715     reader.addExpectedNamespace("number", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0");
0716     reader.addExpectedNamespace("manifest", "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0");
0717     reader.addExpectedNamespace("anim", "urn:oasis:names:tc:opendocument:xmlns:animation:1.0");
0718 
0719     reader.addExpectedNamespace("math", "http://www.w3.org/1998/Math/MathML");
0720     reader.addExpectedNamespace("svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0");
0721     reader.addExpectedNamespace("fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0");
0722     reader.addExpectedNamespace("dc", "http://purl.org/dc/elements/1.1/");
0723     reader.addExpectedNamespace("xlink", "http://www.w3.org/1999/xlink");
0724     reader.addExpectedNamespace("VL", "http://openoffice.org/2001/versions-list");
0725     reader.addExpectedNamespace("smil", "urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0");
0726     reader.addExpectedNamespace("xhtml", "http://www.w3.org/1999/xhtml");
0727     reader.addExpectedNamespace("xml", "http://www.w3.org/XML/1998/namespace");
0728 
0729     reader.addExpectedNamespace("calligra", "http://www.calligra.org/2005/");
0730     reader.addExpectedNamespace("officeooo", "http://openoffice.org/2009/office");
0731     reader.addExpectedNamespace("ooo", "http://openoffice.org/2004/office");
0732 
0733     reader.addExpectedNamespace("delta", "http://www.deltaxml.com/ns/track-changes/delta-namespace");
0734     reader.addExpectedNamespace("split", "http://www.deltaxml.com/ns/track-changes/split-namespace");
0735     reader.addExpectedNamespace("ac", "http://www.deltaxml.com/ns/track-changes/attribute-change-namespace");
0736 
0737     // This list of namespaces is taken from KoXmlReader::fixNamespace()
0738     // They were generated by old versions of OpenOffice.org.
0739     reader.addExtraNamespace("office",    "http://openoffice.org/2000/office");
0740     reader.addExtraNamespace("text",      "http://openoffice.org/2000/text");
0741     reader.addExtraNamespace("style",     "http://openoffice.org/2000/style");
0742     reader.addExtraNamespace("fo",        "http://www.w3.org/1999/XSL/Format");
0743     reader.addExtraNamespace("table",     "http://openoffice.org/2000/table");
0744     reader.addExtraNamespace("drawing",   "http://openoffice.org/2000/drawing");
0745     reader.addExtraNamespace("datastyle", "http://openoffice.org/2000/datastyle");
0746     reader.addExtraNamespace("svg",       "http://www.w3.org/2000/svg");
0747     reader.addExtraNamespace("chart",     "http://openoffice.org/2000/chart");
0748     reader.addExtraNamespace("dr3d",      "http://openoffice.org/2000/dr3d");
0749     reader.addExtraNamespace("form",      "http://openoffice.org/2000/form");
0750     reader.addExtraNamespace("script",    "http://openoffice.org/2000/script");
0751     reader.addExtraNamespace("meta",      "http://openoffice.org/2000/meta");
0752     reader.addExtraNamespace("config",    "http://openoffice.org/2001/config");
0753     reader.addExtraNamespace("pres",      "http://openoffice.org/2000/presentation");
0754     reader.addExtraNamespace("manifest",  "http://openoffice.org/2001/manifest");
0755 }