File indexing completed on 2024-05-12 15:27:01

0001 /***************************************************************************
0002     File                 : XmlStreamReader.cpp
0003     Project              : LabPlot
0004     Description          : XML stream parser that supports errors and warnings
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2009 Tilman Benkert (thzs@gmx.net)
0007     Copyright            : (C) 2015-2016 Alexander Semke (alexander.semke@web.de)
0008  ***************************************************************************/
0009 
0010 /***************************************************************************
0011  *                                                                         *
0012  *  This program is free software; you can redistribute it and/or modify   *
0013  *  it under the terms of the GNU General Public License as published by   *
0014  *  the Free Software Foundation; either version 2 of the License, or      *
0015  *  (at your option) any later version.                                    *
0016  *                                                                         *
0017  *  This program is distributed in the hope that it will be useful,        *
0018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0020  *  GNU General Public License for more details.                           *
0021  *                                                                         *
0022  *   You should have received a copy of the GNU General Public License     *
0023  *   along with this program; if not, write to the Free Software           *
0024  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0025  *   Boston, MA  02110-1301  USA                                           *
0026  *                                                                         *
0027  ***************************************************************************/
0028 
0029 #include "backend/lib/XmlStreamReader.h"
0030 #include <KLocalizedString>
0031 
0032 /**
0033  * \class XmlStreamReader
0034  * \brief XML stream parser that supports errors as well as warnings.
0035  * This class also adds line and column numbers to the error message.
0036  */
0037 XmlStreamReader::XmlStreamReader() = default;
0038 
0039 XmlStreamReader::XmlStreamReader(QIODevice* device) : QXmlStreamReader(device) {
0040 }
0041 
0042 XmlStreamReader::XmlStreamReader(const QByteArray& data) : QXmlStreamReader(data) {
0043 }
0044 
0045 XmlStreamReader::XmlStreamReader(const QString& data) : QXmlStreamReader(data) {
0046 }
0047 
0048 XmlStreamReader::XmlStreamReader(const char* data) : QXmlStreamReader(data) {
0049 }
0050 
0051 const QStringList& XmlStreamReader::warningStrings() const {
0052     return m_warnings;
0053 }
0054 
0055 /*
0056  * returns the human readable string for the missing CAS plugins in case
0057  * the project has some CAS content but the application was either not compiled with
0058  * CAS/Cantor support or the correspongind plugins for the required backends are missing.
0059  *
0060  * The returned text is in the form "Octave" or "Octave and Maxima" or "Octave, Maxima and Python", etc.
0061  */
0062 QString XmlStreamReader::missingCASWarning() const {
0063     const int count = m_missingCASPlugins.count();
0064     if (count == 1)
0065         return m_missingCASPlugins.constFirst();
0066     else {
0067         QString msg;
0068         for (int i = 0; i < count; ++ i) {
0069             if (!msg.isEmpty()) {
0070                 if (i == count - 1)
0071                     msg += QLatin1Char(' ') + i18n("and") + QLatin1Char(' ');
0072                 else
0073                     msg += QLatin1String(", ");
0074             }
0075             msg += m_missingCASPlugins.at(i);
0076         }
0077         return msg;
0078     }
0079 }
0080 
0081 bool XmlStreamReader::hasWarnings() const {
0082     return !m_warnings.isEmpty();
0083 }
0084 
0085 bool XmlStreamReader::hasMissingCASWarnings() const {
0086     return !m_missingCASPlugins.isEmpty();
0087 }
0088 
0089 void XmlStreamReader::setFailedCASMissing(bool value) {
0090     m_failedCASMissing = value;
0091 }
0092 
0093 /*!
0094  * returns \c true if the loading of an project object failed because
0095  * of the missing CAS functionality (no CAS support or missing CAS plugin).
0096  * returns \c false if the loadign failed because of other reasons
0097  * like broken XML or missing important and required attributes.
0098  */
0099 bool XmlStreamReader::failedCASMissing() const {
0100     return m_failedCASMissing;
0101 }
0102 
0103 void XmlStreamReader::raiseError(const QString & message) {
0104     QXmlStreamReader::raiseError(i18n("line %1, column %2: %3", lineNumber(), columnNumber(), message));
0105 }
0106 
0107 void XmlStreamReader::raiseWarning(const QString & message) {
0108     m_warnings.append(i18n("line %1, column %2: %3", lineNumber(), columnNumber(), message));
0109 }
0110 
0111 void XmlStreamReader::raiseMissingCASWarning(const QString& name) {
0112     m_missingCASPlugins.append(name);
0113 }
0114 
0115 /*!
0116   * Go to the next start or end element tag
0117   * If the end of the document is reached, an error is raised.
0118   * \return false if end of document reached, otherwise true
0119   */
0120 bool XmlStreamReader::skipToNextTag() {
0121     if (atEnd()) {
0122         raiseError(i18n("unexpected end of document"));
0123         return false;
0124     }
0125 
0126     do {
0127         readNext();
0128     } while (!(isStartElement() || isEndElement() || atEnd()));
0129 
0130     if (atEnd()) {
0131         raiseError(i18n("unexpected end of document"));
0132         return false;
0133     }
0134 
0135     return true;
0136 }
0137 
0138 /*!
0139   * Go to the end element tag of the current element
0140   * If the end of the document is reached, an error is raised.
0141   * \return false if end of document reached, otherwise true
0142   */
0143 bool XmlStreamReader::skipToEndElement() {
0144     int depth = 1;
0145     if (atEnd()) {
0146         raiseError(i18n("unexpected end of document"));
0147         return false;
0148     }
0149 
0150     do {
0151         readNext();
0152         if (isEndElement()) depth--;
0153         if (isStartElement()) depth++;
0154     } while (!((isEndElement() && depth == 0) || atEnd()));
0155 
0156     if (atEnd()) {
0157         raiseError(i18n("unexpected end of document"));
0158         return false;
0159     }
0160 
0161     return true;
0162 }
0163 
0164 /*!
0165  * Read an XML attribute and convert it to int
0166   * \param name attribute name
0167   * \param ok pointer to report back whether the attribute value could be determined (may be NULL)
0168   * \return the attribute value if found and converted, otherwise zero (in this case *ok is false)
0169   */
0170 int XmlStreamReader::readAttributeInt(const QString& name, bool* ok) {
0171     QString str = attributes().value(namespaceUri().toString(), name).toString();
0172     if (str.isEmpty()) {
0173         if (ok) *ok = false;
0174         return 0;
0175     }
0176 
0177     return str.toInt(ok);
0178 }