summaryrefslogtreecommitdiffstats
path: root/src/linguist
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2019-11-08 16:49:12 +0100
committerSona Kurazyan <sona.kurazyan@qt.io>2020-01-08 14:43:09 +0100
commit9e6943370585bdc791caae6c83555b3aa5efe063 (patch)
tree174f3087a38ccbb6f9143311a6436248cbda9d1e /src/linguist
parente3f1d3fef117d6dbf7952995506ef1dec9423067 (diff)
Stop using SAX classes
SAX classes for parsing XML documents will be deprecated soon. Re-implemented SAX-based xml parsing classes using QXmlStreamReader. All the parsers now inherit from XmlParser, which drives the parsing loop and allows overriding the methods for handling different XML tokens in a specific way depending on the use-case. Task-number: QTBUG-76177 Change-Id: I5393cc7218beffb4e48187e435c89d1d179deb37 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'src/linguist')
-rw-r--r--src/linguist/linguist/linguist.pro2
-rw-r--r--src/linguist/linguist/messagemodel.h2
-rw-r--r--src/linguist/linguist/phrase.cpp80
-rw-r--r--src/linguist/lupdate/ui.cpp99
-rw-r--r--src/linguist/shared/formats.pri10
-rw-r--r--src/linguist/shared/xliff.cpp122
-rw-r--r--src/linguist/shared/xmlparser.cpp109
-rw-r--r--src/linguist/shared/xmlparser.h63
8 files changed, 323 insertions, 164 deletions
diff --git a/src/linguist/linguist/linguist.pro b/src/linguist/linguist/linguist.pro
index af74df8ec..d083896c3 100644
--- a/src/linguist/linguist/linguist.pro
+++ b/src/linguist/linguist/linguist.pro
@@ -1,4 +1,4 @@
-QT += core-private gui-private widgets xml uitools-private printsupport
+QT += core-private gui-private widgets uitools-private printsupport
DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
diff --git a/src/linguist/linguist/messagemodel.h b/src/linguist/linguist/messagemodel.h
index 5c2d95ec2..32f868d51 100644
--- a/src/linguist/linguist/messagemodel.h
+++ b/src/linguist/linguist/messagemodel.h
@@ -37,8 +37,6 @@
#include <QtCore/QLocale>
#include <QtGui/QColor>
#include <QtGui/QBitmap>
-#include <QtXml/QXmlDefaultHandler>
-
QT_BEGIN_NAMESPACE
diff --git a/src/linguist/linguist/phrase.cpp b/src/linguist/linguist/phrase.cpp
index b7b9835f5..064e79f40 100644
--- a/src/linguist/linguist/phrase.cpp
+++ b/src/linguist/linguist/phrase.cpp
@@ -28,6 +28,7 @@
#include "phrase.h"
#include "translator.h"
+#include "xmlparser.h"
#include <QApplication>
#include <QFile>
@@ -36,9 +37,7 @@
#include <QRegExp>
#include <QTextCodec>
#include <QTextStream>
-#include <QXmlAttributes>
-#include <QXmlDefaultHandler>
-#include <QXmlParseException>
+#include <QXmlStreamReader>
QT_BEGIN_NAMESPACE
@@ -104,24 +103,26 @@ bool operator==(const Phrase &p, const Phrase &q)
p.definition() == q.definition() && p.phraseBook() == q.phraseBook();
}
-class QphHandler : public QXmlDefaultHandler
+class QphHandler : public XmlParser
{
public:
- QphHandler(PhraseBook *phraseBook)
- : pb(phraseBook), ferrorCount(0) { }
-
- virtual bool startElement(const QString &namespaceURI,
- const QString &localName, const QString &qName,
- const QXmlAttributes &atts);
- virtual bool endElement(const QString &namespaceURI,
- const QString &localName, const QString &qName);
- virtual bool characters(const QString &ch);
- virtual bool fatalError(const QXmlParseException &exception);
+ QphHandler(PhraseBook *phraseBook, QXmlStreamReader &reader)
+ : XmlParser(reader), pb(phraseBook), ferrorCount(0)
+ {
+ }
+ ~QphHandler() override = default;
QString language() const { return m_language; }
QString sourceLanguage() const { return m_sourceLanguage; }
private:
+ bool startElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName, const QXmlStreamAttributes &atts) override;
+ bool endElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName) override;
+ bool characters(const QStringRef &ch) override;
+ bool fatalError(qint64 line, qint64 column, const QString &message) override;
+
PhraseBook *pb;
QString source;
QString target;
@@ -133,14 +134,15 @@ private:
int ferrorCount;
};
-bool QphHandler::startElement(const QString & /* namespaceURI */,
- const QString & /* localName */,
- const QString &qName,
- const QXmlAttributes &atts)
+bool QphHandler::startElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName, const QXmlStreamAttributes &atts)
{
+ Q_UNUSED(namespaceURI)
+ Q_UNUSED(localName)
+
if (qName == QLatin1String("QPH")) {
- m_language = atts.value(QLatin1String("language"));
- m_sourceLanguage = atts.value(QLatin1String("sourcelanguage"));
+ m_language = atts.value(QLatin1String("language")).toString();
+ m_sourceLanguage = atts.value(QLatin1String("sourcelanguage")).toString();
} else if (qName == QLatin1String("phrase")) {
source.truncate(0);
target.truncate(0);
@@ -150,10 +152,12 @@ bool QphHandler::startElement(const QString & /* namespaceURI */,
return true;
}
-bool QphHandler::endElement(const QString & /* namespaceURI */,
- const QString & /* localName */,
- const QString &qName)
+bool QphHandler::endElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName)
{
+ Q_UNUSED(namespaceURI)
+ Q_UNUSED(localName)
+
if (qName == QLatin1String("source"))
source = accum;
else if (qName == QLatin1String("target"))
@@ -165,20 +169,20 @@ bool QphHandler::endElement(const QString & /* namespaceURI */,
return true;
}
-bool QphHandler::characters(const QString &ch)
+bool QphHandler::characters(const QStringRef &ch)
{
accum += ch;
return true;
}
-bool QphHandler::fatalError(const QXmlParseException &exception)
+bool QphHandler::fatalError(qint64 line, qint64 column, const QString &message)
{
if (ferrorCount++ == 0) {
QString msg = PhraseBook::tr("Parse error at line %1, column %2 (%3).")
- .arg(exception.lineNumber()).arg(exception.columnNumber())
- .arg(exception.message());
- QMessageBox::information(0,
- QObject::tr("Qt Linguist"), msg);
+ .arg(line)
+ .arg(column)
+ .arg(message);
+ QMessageBox::information(nullptr, QObject::tr("Qt Linguist"), msg);
}
return false;
}
@@ -223,20 +227,10 @@ bool PhraseBook::load(const QString &fileName, bool *langGuessed)
m_fileName = fileName;
- QXmlInputSource in(&f);
- QXmlSimpleReader reader;
- // don't click on these!
- reader.setFeature(QLatin1String("http://xml.org/sax/features/namespaces"), false);
- reader.setFeature(QLatin1String("http://xml.org/sax/features/namespace-prefixes"), true);
- reader.setFeature(QLatin1String("http://trolltech.com/xml/features/report-whitespace"
- "-only-CharData"), false);
- QphHandler *hand = new QphHandler(this);
- reader.setContentHandler(hand);
- reader.setErrorHandler(hand);
-
- bool ok = reader.parse(in);
- reader.setContentHandler(0);
- reader.setErrorHandler(0);
+ QXmlStreamReader reader(&f);
+ QphHandler *hand = new QphHandler(this, reader);
+ reader.setNamespaceProcessing(false);
+ bool ok = hand->parse();
Translator::languageAndCountry(hand->language(), &m_language, &m_country);
*langGuessed = false;
diff --git a/src/linguist/lupdate/ui.cpp b/src/linguist/lupdate/ui.cpp
index ce4ecc045..f91ffac5b 100644
--- a/src/linguist/lupdate/ui.cpp
+++ b/src/linguist/lupdate/ui.cpp
@@ -29,40 +29,41 @@
#include "lupdate.h"
#include <translator.h>
+#include <xmlparser.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QString>
-
-#include <QtXml/QXmlAttributes>
-#include <QtXml/QXmlDefaultHandler>
-#include <QtXml/QXmlLocator>
-#include <QtXml/QXmlParseException>
-
+#include <QtCore/QXmlStreamReader>
QT_BEGIN_NAMESPACE
-class UiReader : public QXmlDefaultHandler
+class UiReader : public XmlParser
{
public:
- UiReader(Translator &translator, ConversionData &cd)
- : m_translator(translator), m_cd(cd), m_lineNumber(-1), m_isTrString(false),
- m_insideStringList(false), m_idBasedTranslations(false)
- {}
-
- bool startElement(const QString &namespaceURI, const QString &localName,
- const QString &qName, const QXmlAttributes &atts);
- bool endElement(const QString &namespaceURI, const QString &localName,
- const QString &qName);
- bool characters(const QString &ch);
- bool fatalError(const QXmlParseException &exception);
-
- void setDocumentLocator(QXmlLocator *locator) { m_locator = locator; }
+ UiReader(Translator &translator, ConversionData &cd, QXmlStreamReader &reader)
+ : XmlParser(reader),
+ m_translator(translator),
+ m_cd(cd),
+ m_lineNumber(-1),
+ m_isTrString(false),
+ m_insideStringList(false),
+ m_idBasedTranslations(false)
+ {
+ }
+ ~UiReader() override = default;
private:
+ bool startElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName, const QXmlStreamAttributes &atts) override;
+ bool endElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName) override;
+ bool characters(const QStringRef &ch) override;
+ bool fatalError(qint64 line, qint64 column, const QString &message) override;
+
void flush();
- void readTranslationAttributes(const QXmlAttributes &atts);
+ void readTranslationAttributes(const QXmlStreamAttributes &atts);
Translator &m_translator;
ConversionData &m_cd;
@@ -71,7 +72,6 @@ private:
QString m_comment;
QString m_extracomment;
QString m_id;
- QXmlLocator *m_locator;
QString m_accum;
int m_lineNumber;
@@ -80,8 +80,8 @@ private:
bool m_idBasedTranslations;
};
-bool UiReader::startElement(const QString &namespaceURI,
- const QString &localName, const QString &qName, const QXmlAttributes &atts)
+bool UiReader::startElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName, const QXmlStreamAttributes &atts)
{
Q_UNUSED(namespaceURI);
Q_UNUSED(localName);
@@ -95,16 +95,16 @@ bool UiReader::startElement(const QString &namespaceURI,
m_insideStringList = true;
readTranslationAttributes(atts);
} else if (qName == QLatin1String("ui")) { // UI "header"
- const int translationTypeIndex = atts.index(QStringLiteral("idbasedtr"));
- m_idBasedTranslations = translationTypeIndex >= 0
- && atts.value(translationTypeIndex) == QLatin1String("true");
+ const auto attr = QStringLiteral("idbasedtr");
+ m_idBasedTranslations =
+ atts.hasAttribute(attr) && atts.value(attr) == QLatin1String("true");
}
m_accum.clear();
return true;
}
-bool UiReader::endElement(const QString &namespaceURI,
- const QString &localName, const QString &qName)
+bool UiReader::endElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName)
{
Q_UNUSED(namespaceURI);
Q_UNUSED(localName);
@@ -127,17 +127,18 @@ bool UiReader::endElement(const QString &namespaceURI,
return true;
}
-bool UiReader::characters(const QString &ch)
+bool UiReader::characters(const QStringRef &ch)
{
- m_accum += ch;
+ m_accum += ch.toString();
return true;
}
-bool UiReader::fatalError(const QXmlParseException &exception)
+bool UiReader::fatalError(qint64 line, qint64 column, const QString &message)
{
QString msg = LU::tr("XML error: Parse error at line %1, column %2 (%3).")
- .arg(exception.lineNumber()).arg(exception.columnNumber())
- .arg(exception.message());
+ .arg(line)
+ .arg(column)
+ .arg(message);
m_cd.appendError(msg);
return false;
}
@@ -160,17 +161,17 @@ void UiReader::flush()
}
}
-void UiReader::readTranslationAttributes(const QXmlAttributes &atts)
+void UiReader::readTranslationAttributes(const QXmlStreamAttributes &atts)
{
- const QString notr = atts.value(QStringLiteral("notr"));
+ const auto notr = atts.value(QStringLiteral("notr"));
if (notr.isEmpty() || notr != QStringLiteral("true")) {
m_isTrString = true;
- m_comment = atts.value(QStringLiteral("comment"));
- m_extracomment = atts.value(QStringLiteral("extracomment"));
+ m_comment = atts.value(QStringLiteral("comment")).toString();
+ m_extracomment = atts.value(QStringLiteral("extracomment")).toString();
if (m_idBasedTranslations)
- m_id = atts.value(QStringLiteral("id"));
+ m_id = atts.value(QStringLiteral("id")).toString();
if (!m_cd.m_noUiLines)
- m_lineNumber = m_locator->lineNumber();
+ m_lineNumber = static_cast<int>(reader.lineNumber());
} else {
m_isTrString = false;
}
@@ -184,20 +185,14 @@ bool loadUI(Translator &translator, const QString &filename, ConversionData &cd)
cd.appendError(LU::tr("Cannot open %1: %2").arg(filename, file.errorString()));
return false;
}
- QXmlInputSource in(&file);
- QXmlSimpleReader reader;
- reader.setFeature(QLatin1String("http://xml.org/sax/features/namespaces"), false);
- reader.setFeature(QLatin1String("http://xml.org/sax/features/namespace-prefixes"), true);
- reader.setFeature(QLatin1String(
- "http://trolltech.com/xml/features/report-whitespace-only-CharData"), false);
- UiReader handler(translator, cd);
- reader.setContentHandler(&handler);
- reader.setErrorHandler(&handler);
- bool result = reader.parse(in);
+
+ QXmlStreamReader reader(&file);
+ reader.setNamespaceProcessing(false);
+
+ UiReader uiReader(translator, cd, reader);
+ bool result = uiReader.parse();
if (!result)
cd.appendError(LU::tr("Parse error in UI file"));
- reader.setContentHandler(0);
- reader.setErrorHandler(0);
return result;
}
diff --git a/src/linguist/shared/formats.pri b/src/linguist/shared/formats.pri
index e5f388f2a..d77dacac5 100644
--- a/src/linguist/shared/formats.pri
+++ b/src/linguist/shared/formats.pri
@@ -1,17 +1,15 @@
-
-# infrastructure
-QT *= xml
-
INCLUDEPATH *= $$PWD
SOURCES += \
$$PWD/numerus.cpp \
$$PWD/translator.cpp \
- $$PWD/translatormessage.cpp
+ $$PWD/translatormessage.cpp \
+ $$PWD/xmlparser.cpp
HEADERS += \
$$PWD/translator.h \
- $$PWD/translatormessage.h
+ $$PWD/translatormessage.h \
+ $$PWF/xmlparser.h
# "real" formats readers and writers
SOURCES += \
diff --git a/src/linguist/shared/xliff.cpp b/src/linguist/shared/xliff.cpp
index c499e9ea5..bc47289b4 100644
--- a/src/linguist/shared/xliff.cpp
+++ b/src/linguist/shared/xliff.cpp
@@ -27,6 +27,7 @@
****************************************************************************/
#include "translator.h"
+#include "xmlparser.h"
#include <QtCore/QDebug>
#include <QtCore/QMap>
@@ -36,11 +37,6 @@
#include <QtCore/QTextCodec>
#include <QtCore/QTextStream>
-#include <QtXml/QXmlAttributes>
-#include <QtXml/QXmlDefaultHandler>
-#include <QtXml/QXmlParseException>
-
-
// The string value is historical and reflects the main purpose: Keeping
// obsolete entries separate from the magic file message (which both have
// no location information, but typically reside at opposite ends of the file).
@@ -368,22 +364,22 @@ static void writeMessage(QTextStream &ts, const TranslatorMessage &msg, const QR
}
}
-
-class XLIFFHandler : public QXmlDefaultHandler
+class XLIFFHandler : public XmlParser
{
public:
- XLIFFHandler(Translator &translator, ConversionData &cd);
+ XLIFFHandler(Translator &translator, ConversionData &cd, QXmlStreamReader &reader);
+ ~XLIFFHandler() override = default;
- bool startElement(const QString& namespaceURI, const QString &localName,
- const QString &qName, const QXmlAttributes &atts );
- bool endElement(const QString& namespaceURI, const QString &localName,
- const QString &qName );
- bool characters(const QString &ch);
- bool fatalError(const QXmlParseException &exception);
+private:
+ bool startElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName, const QXmlStreamAttributes &atts) override;
+ bool endElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName) override;
+ bool characters(const QStringRef &ch) override;
+ bool fatalError(qint64 line, qint64 column, const QString &message) override;
- bool endDocument();
+ bool endDocument() override;
-private:
enum XliffContext {
XC_xliff,
XC_group,
@@ -442,14 +438,16 @@ private:
QStack<int> m_contextStack;
};
-XLIFFHandler::XLIFFHandler(Translator &translator, ConversionData &cd)
- : m_translator(translator), m_cd(cd),
- m_translate(true),
- m_approved(true),
- m_lineNumber(-1),
- m_URITT(QLatin1String(TrollTsNamespaceURI)),
- m_URI(QLatin1String(XLIFF11namespaceURI)),
- m_URI12(QLatin1String(XLIFF12namespaceURI))
+XLIFFHandler::XLIFFHandler(Translator &translator, ConversionData &cd, QXmlStreamReader &reader)
+ : XmlParser(reader, true),
+ m_translator(translator),
+ m_cd(cd),
+ m_translate(true),
+ m_approved(true),
+ m_lineNumber(-1),
+ m_URITT(QLatin1String(TrollTsNamespaceURI)),
+ m_URI(QLatin1String(XLIFF11namespaceURI)),
+ m_URI12(QLatin1String(XLIFF12namespaceURI))
{}
@@ -485,33 +483,35 @@ bool XLIFFHandler::hasContext(XliffContext ctx) const
return false;
}
-bool XLIFFHandler::startElement(const QString& namespaceURI,
- const QString &localName, const QString &qName, const QXmlAttributes &atts )
+bool XLIFFHandler::startElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName, const QXmlStreamAttributes &atts)
{
Q_UNUSED(qName);
if (namespaceURI == m_URITT)
goto bail;
- if (namespaceURI != m_URI && namespaceURI != m_URI12)
- return false;
+ if (namespaceURI != m_URI && namespaceURI != m_URI12) {
+ return fatalError(reader.lineNumber(), reader.columnNumber(),
+ QLatin1String("Unknown namespace in the XLIFF file"));
+ }
if (localName == QLatin1String("xliff")) {
// make sure that the stack is not empty during parsing
pushContext(XC_xliff);
} else if (localName == QLatin1String("file")) {
- m_fileName = atts.value(QLatin1String("original"));
- m_language = atts.value(QLatin1String("target-language"));
+ m_fileName = atts.value(QLatin1String("original")).toString();
+ m_language = atts.value(QLatin1String("target-language")).toString();
m_language.replace(QLatin1Char('-'), QLatin1Char('_'));
- m_sourceLanguage = atts.value(QLatin1String("source-language"));
+ m_sourceLanguage = atts.value(QLatin1String("source-language")).toString();
m_sourceLanguage.replace(QLatin1Char('-'), QLatin1Char('_'));
if (m_sourceLanguage == QLatin1String("en"))
m_sourceLanguage.clear();
} else if (localName == QLatin1String("group")) {
if (atts.value(QLatin1String("restype")) == QLatin1String(restypeContext)) {
- m_context = atts.value(QLatin1String("resname"));
+ m_context = atts.value(QLatin1String("resname")).toString();
pushContext(XC_restype_context);
} else {
if (atts.value(QLatin1String("restype")) == QLatin1String(restypePlurals)) {
pushContext(XC_restype_plurals);
- m_id = atts.value(QLatin1String("id"));
+ m_id = atts.value(QLatin1String("id")).toString();
if (atts.value(QLatin1String("translate")) == QLatin1String("no"))
m_translate = false;
} else {
@@ -523,7 +523,7 @@ bool XLIFFHandler::startElement(const QString& namespaceURI,
if (atts.value(QLatin1String("translate")) == QLatin1String("no"))
m_translate = false;
if (!hasContext(XC_restype_plurals)) {
- m_id = atts.value(QLatin1String("id"));
+ m_id = atts.value(QLatin1String("id")).toString();
if (m_id.startsWith(QLatin1String("_msg")))
m_id.clear();
}
@@ -539,19 +539,18 @@ bool XLIFFHandler::startElement(const QString& namespaceURI,
if (atts.value(QLatin1String("restype")) != QLatin1String(restypeDummy))
pushContext(XC_restype_translation);
} else if (localName == QLatin1String("context-group")) {
- QString purpose = atts.value(QLatin1String("purpose"));
- if (purpose == QLatin1String("location"))
+ if (atts.value(QLatin1String("purpose")) == QLatin1String("location"))
pushContext(XC_context_group);
else
pushContext(XC_context_group_any);
} else if (currentContext() == XC_context_group && localName == QLatin1String("context")) {
- QString ctxtype = atts.value(QLatin1String("context-type"));
+ const auto ctxtype = atts.value(QLatin1String("context-type"));
if (ctxtype == QLatin1String("linenumber"))
pushContext(XC_context_linenumber);
else if (ctxtype == QLatin1String("sourcefile"))
pushContext(XC_context_filename);
} else if (currentContext() == XC_context_group_any && localName == QLatin1String("context")) {
- QString ctxtype = atts.value(QLatin1String("context-type"));
+ const auto ctxtype = atts.value(QLatin1String("context-type"));
if (ctxtype == QLatin1String(contextMsgctxt))
pushContext(XC_context_comment);
else if (ctxtype == QLatin1String(contextOldMsgctxt))
@@ -563,7 +562,7 @@ bool XLIFFHandler::startElement(const QString& namespaceURI,
else
pushContext(XC_translator_comment);
} else if (localName == QLatin1String("ph")) {
- QString ctype = atts.value(QLatin1String("ctype"));
+ QString ctype = atts.value(QLatin1String("ctype")).toString();
if (ctype.startsWith(QLatin1String("x-ch-")))
m_ctype = ctype.mid(5);
pushContext(XC_ph);
@@ -574,19 +573,21 @@ bail:
return true;
}
-bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localName,
- const QString &qName)
+bool XLIFFHandler::endElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName)
{
Q_UNUSED(qName);
if (namespaceURI == m_URITT) {
if (hasContext(XC_trans_unit) || hasContext(XC_restype_plurals))
- m_extra[localName] = accum;
+ m_extra[localName.toString()] = accum;
else
- m_translator.setExtra(localName, accum);
+ m_translator.setExtra(localName.toString(), accum);
return true;
}
- if (namespaceURI != m_URI && namespaceURI != m_URI12)
- return false;
+ if (namespaceURI != m_URI && namespaceURI != m_URI12) {
+ return fatalError(reader.lineNumber(), reader.columnNumber(),
+ QLatin1String("Unknown namespace in the XLIFF file"));
+ }
//qDebug() << "URI:" << namespaceURI << "QNAME:" << qName;
if (localName == QLatin1String("xliff")) {
popContext(XC_xliff);
@@ -640,15 +641,19 @@ bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localN
if (!m_hadAlt)
m_oldSources.append(QString());
if (!hasContext(XC_restype_plurals)) {
- if (!finalizeMessage(false))
- return false;
+ if (!finalizeMessage(false)) {
+ return fatalError(reader.lineNumber(), reader.columnNumber(),
+ QLatin1String("Element processing failed"));
+ }
}
} else if (localName == QLatin1String("alt-trans")) {
popContext(XC_alt_trans);
} else if (localName == QLatin1String("group")) {
if (popContext(XC_restype_plurals)) {
- if (!finalizeMessage(true))
- return false;
+ if (!finalizeMessage(true)) {
+ return fatalError(reader.lineNumber(), reader.columnNumber(),
+ QLatin1String("Element processing failed"));
+ }
} else if (popContext(XC_restype_context)) {
m_context.clear();
} else {
@@ -658,7 +663,7 @@ bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localN
return true;
}
-bool XLIFFHandler::characters(const QString &ch)
+bool XLIFFHandler::characters(const QStringRef &ch)
{
if (currentContext() == XC_ph) {
// handle the content of <ph> elements
@@ -670,7 +675,7 @@ bool XLIFFHandler::characters(const QString &ch)
accum.append(chr);
}
} else {
- QString t = ch;
+ QString t = ch.toString();
t.replace(QLatin1String("\r"), QLatin1String(""));
accum.append(t);
}
@@ -730,23 +735,20 @@ bool XLIFFHandler::finalizeMessage(bool isPlural)
return true;
}
-bool XLIFFHandler::fatalError(const QXmlParseException &exception)
+bool XLIFFHandler::fatalError(qint64 line, qint64 column, const QString &message)
{
QString msg = QString::asprintf("XML error: Parse error at line %d, column %d (%s).\n",
- exception.lineNumber(), exception.columnNumber(),
- exception.message().toLatin1().data());
+ static_cast<int>(line), static_cast<int>(column),
+ message.toLatin1().data());
m_cd.appendError(msg);
return false;
}
bool loadXLIFF(Translator &translator, QIODevice &dev, ConversionData &cd)
{
- QXmlInputSource in(&dev);
- QXmlSimpleReader reader;
- XLIFFHandler hand(translator, cd);
- reader.setContentHandler(&hand);
- reader.setErrorHandler(&hand);
- return reader.parse(in);
+ QXmlStreamReader reader(&dev);
+ XLIFFHandler hand(translator, cd, reader);
+ return hand.parse();
}
bool saveXLIFF(const Translator &translator, QIODevice &dev, ConversionData &cd)
diff --git a/src/linguist/shared/xmlparser.cpp b/src/linguist/shared/xmlparser.cpp
new file mode 100644
index 000000000..bcdca12bb
--- /dev/null
+++ b/src/linguist/shared/xmlparser.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Linguist of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "xmlparser.h"
+
+QT_BEGIN_NAMESPACE
+
+bool XmlParser::parse()
+{
+ while (!reader.atEnd()) {
+ reader.readNext();
+ if (reader.hasError()) {
+ fatalError(reader.lineNumber(), reader.columnNumber(), reader.errorString());
+ return false;
+ }
+
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (!startElement(reader.namespaceUri(), reader.name(), reader.qualifiedName(),
+ reader.attributes())) {
+ return false;
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ if (!endElement(reader.namespaceUri(), reader.name(), reader.qualifiedName())) {
+ return false;
+ }
+ break;
+ case QXmlStreamReader::Characters:
+ if (reportWhitespaceOnlyData
+ || (!reader.isWhitespace() && !reader.text().toString().trimmed().isEmpty())) {
+ if (!characters(reader.text()))
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (reader.isEndDocument() && !endDocument())
+ return false;
+
+ return true;
+}
+
+bool XmlParser::startElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName, const QXmlStreamAttributes &atts)
+{
+ Q_UNUSED(namespaceURI)
+ Q_UNUSED(localName)
+ Q_UNUSED(qName)
+ Q_UNUSED(atts)
+ return true;
+}
+
+bool XmlParser::endElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName)
+{
+ Q_UNUSED(namespaceURI)
+ Q_UNUSED(localName)
+ Q_UNUSED(qName)
+ return true;
+}
+
+bool XmlParser::characters(const QStringRef &text)
+{
+ Q_UNUSED(text)
+ return true;
+}
+
+bool XmlParser::fatalError(qint64 line, qint64 column, const QString &message)
+{
+ Q_UNUSED(line)
+ Q_UNUSED(column)
+ Q_UNUSED(message)
+ return true;
+}
+
+bool XmlParser::endDocument()
+{
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/linguist/shared/xmlparser.h b/src/linguist/shared/xmlparser.h
new file mode 100644
index 000000000..4028c7067
--- /dev/null
+++ b/src/linguist/shared/xmlparser.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Linguist of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef XMLPARSER_H
+#define XMLPARSER_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qxmlstream.h>
+
+QT_BEGIN_NAMESPACE
+
+class XmlParser
+{
+public:
+ XmlParser(QXmlStreamReader &r, bool whitespaceOnlyData = false)
+ : reader(r), reportWhitespaceOnlyData(whitespaceOnlyData)
+ {
+ }
+ virtual ~XmlParser() = default;
+
+ bool parse();
+
+protected:
+ virtual bool startElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName, const QXmlStreamAttributes &atts);
+ virtual bool endElement(const QStringRef &namespaceURI, const QStringRef &localName,
+ const QStringRef &qName);
+ virtual bool characters(const QStringRef &text);
+ virtual bool endDocument();
+ virtual bool fatalError(qint64 line, qint64 column, const QString &message);
+
+ QXmlStreamReader &reader;
+ bool reportWhitespaceOnlyData;
+};
+
+QT_END_NAMESPACE
+
+#endif // XMLPARSER_H