summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Tardon <dtardon@redhat.com>2017-05-17 13:27:41 +0200
committerDavid Tardon <dtardon@redhat.com>2017-05-17 13:27:41 +0200
commit2a17664d1ce065c75094a05ff29a4feded742aa7 (patch)
treee09cac8f3cc1cc52d05a3e68e01e7ed8c8da7990
parent39a8567ff10e2b3ca4c7a3be0d6604cb881819f4 (diff)
improve check for stuck XML parser
This fixes regression in parsing some broken documents caused by commit 442b4812cf058481e00c186ef738c990e1a50284 . Change-Id: Id4afc8b120c72cb77f27c71c3f1452e100f86faf
-rw-r--r--src/lib/ABWParser.cpp6
-rw-r--r--src/lib/ABWXMLHelper.cpp39
-rw-r--r--src/lib/ABWXMLHelper.h22
3 files changed, 47 insertions, 20 deletions
diff --git a/src/lib/ABWParser.cpp b/src/lib/ABWParser.cpp
index 16826e2..db3c68c 100644
--- a/src/lib/ABWParser.cpp
+++ b/src/lib/ABWParser.cpp
@@ -166,12 +166,12 @@ bool libabw::ABWParser::processXmlDocument(librevenge::RVNGInputStream *input)
if (!input)
return false;
- ABWXMLErrorWatcher watcher;
+ ABWXMLProgressWatcher watcher;
auto reader(xmlReaderForStream(input, &watcher));
if (!reader)
return false;
int ret = xmlTextReaderRead(reader.get());
- while (1 == ret && !watcher.isError())
+ while (1 == ret && !watcher.isStuck())
{
processXmlNode(reader.get());
ret = xmlTextReaderRead(reader.get());
@@ -179,7 +179,7 @@ bool libabw::ABWParser::processXmlDocument(librevenge::RVNGInputStream *input)
if (m_collector)
m_collector->endDocument();
- return !watcher.isError();
+ return ret == 1 && !watcher.isStuck();
}
void libabw::ABWParser::processXmlNode(xmlTextReaderPtr reader)
diff --git a/src/lib/ABWXMLHelper.cpp b/src/lib/ABWXMLHelper.cpp
index 4295c47..fe8638e 100644
--- a/src/lib/ABWXMLHelper.cpp
+++ b/src/lib/ABWXMLHelper.cpp
@@ -51,7 +51,7 @@ extern "C" {
static void abwxmlReaderErrorFunc(void *arg, const char *, xmlParserSeverities severity, xmlTextReaderLocatorPtr)
#endif
{
- const auto watcher = reinterpret_cast<ABWXMLErrorWatcher *>(arg);
+ const auto watcher = reinterpret_cast<ABWXMLProgressWatcher *>(arg);
switch (severity)
{
case XML_PARSER_SEVERITY_VALIDITY_WARNING:
@@ -66,7 +66,7 @@ extern "C" {
case XML_PARSER_SEVERITY_ERROR:
ABW_DEBUG_MSG(("Found xml parser severity error %s\n", message));
if (watcher)
- watcher->setError();
+ watcher->signalError();
break;
default:
break;
@@ -92,29 +92,50 @@ ABWXMLString::operator const char *() const
return reinterpret_cast<const char *>(m_xml.get());
}
-ABWXMLErrorWatcher::ABWXMLErrorWatcher()
- : m_error(false)
+ABWXMLProgressWatcher::ABWXMLProgressWatcher()
+ : m_reader(nullptr)
+ , m_line(0)
+ , m_col(0)
+ , m_wasError(false)
+ , m_isStuck(false)
{
}
-bool ABWXMLErrorWatcher::isError() const
+void ABWXMLProgressWatcher::setReader(xmlTextReaderPtr reader)
{
- return m_error;
+ m_reader = reader;
}
-void ABWXMLErrorWatcher::setError()
+bool ABWXMLProgressWatcher::isStuck() const
{
- m_error = true;
+ return m_isStuck;
+}
+
+void ABWXMLProgressWatcher::signalError()
+{
+ if (m_reader && !m_isStuck)
+ {
+ const int line = m_line;
+ const int col = m_col;
+ const bool checkStuck = m_wasError;
+ m_wasError = true;
+ m_line = xmlTextReaderGetParserLineNumber(m_reader);
+ m_col = xmlTextReaderGetParserColumnNumber(m_reader);
+ if (checkStuck)
+ m_isStuck = line == m_line && col == m_col;
+ }
}
// xmlTextReader helper function
-std::unique_ptr<xmlTextReader, void(*)(xmlTextReaderPtr)> xmlReaderForStream(librevenge::RVNGInputStream *input, ABWXMLErrorWatcher *watcher)
+std::unique_ptr<xmlTextReader, void(*)(xmlTextReaderPtr)> xmlReaderForStream(librevenge::RVNGInputStream *input, ABWXMLProgressWatcher *watcher)
{
std::unique_ptr<xmlTextReader, void(*)(xmlTextReaderPtr)> reader(
xmlReaderForIO(abwxmlInputReadFunc, abwxmlInputCloseFunc, (void *)input, 0, 0,
XML_PARSE_NOBLANKS|XML_PARSE_NOENT|XML_PARSE_NONET|XML_PARSE_RECOVER),
xmlFreeTextReader);
+ if (watcher)
+ watcher->setReader(reader.get());
if (reader)
xmlTextReaderSetErrorHandler(reader.get(), abwxmlReaderErrorFunc, watcher);
return reader;
diff --git a/src/lib/ABWXMLHelper.h b/src/lib/ABWXMLHelper.h
index 5cd6b2c..b657b19 100644
--- a/src/lib/ABWXMLHelper.h
+++ b/src/lib/ABWXMLHelper.h
@@ -34,23 +34,29 @@ private:
std::shared_ptr<xmlChar> m_xml;
};
-class ABWXMLErrorWatcher
+class ABWXMLProgressWatcher
{
- ABWXMLErrorWatcher(const ABWXMLErrorWatcher &) = delete;
- ABWXMLErrorWatcher &operator=(const ABWXMLErrorWatcher &) = delete;
+ ABWXMLProgressWatcher(const ABWXMLProgressWatcher &) = delete;
+ ABWXMLProgressWatcher &operator=(const ABWXMLProgressWatcher &) = delete;
public:
- ABWXMLErrorWatcher();
+ ABWXMLProgressWatcher();
- bool isError() const;
- void setError();
+ void setReader(xmlTextReaderPtr reader);
+
+ bool isStuck() const;
+ void signalError();
private:
- bool m_error;
+ xmlTextReaderPtr m_reader;
+ int m_line;
+ int m_col;
+ bool m_wasError;
+ bool m_isStuck;
};
// create an xmlTextReader pointer from a librevenge::RVNGInputStream pointer
-std::unique_ptr<xmlTextReader, void(*)(xmlTextReaderPtr)> xmlReaderForStream(librevenge::RVNGInputStream *input, ABWXMLErrorWatcher *watcher = 0);
+std::unique_ptr<xmlTextReader, void(*)(xmlTextReaderPtr)> xmlReaderForStream(librevenge::RVNGInputStream *input, ABWXMLProgressWatcher *watcher = 0);
} // namespace libabw