summaryrefslogtreecommitdiff
path: root/sax
diff options
context:
space:
mode:
authorMichael Stahl <mstahl@redhat.com>2015-07-03 23:49:08 +0200
committerMichael Stahl <mstahl@redhat.com>2015-07-04 00:17:49 +0200
commit3c45bfb0cabf206f6217f1de9eb5cfa12b78e46f (patch)
treee4e172b3af8b4d0690085dd8c0688933d35bae1b /sax
parentcf17befa261fd64f95bb4db932ce4d7e149f4a72 (diff)
sax: FastSaxSerializer well-formed element test in presence of ...
... the maMarkStack, which causes the order of calls to startFastElement()/endFastElement() to differ from the order of the tags that are written into the output. This is an attempt to improve the assertions, but if an assertion fails it's generally not obvious where the problem actually is since the unpredictable order may cause the problem to be detected and reported much later than its root cause. Let's see if this finds any new problems in export testing. Change-Id: I97699cc8ef9b18ea9f4f221d5210134feecf0336
Diffstat (limited to 'sax')
-rw-r--r--sax/source/tools/fastserializer.cxx155
-rw-r--r--sax/source/tools/fastserializer.hxx9
2 files changed, 160 insertions, 4 deletions
diff --git a/sax/source/tools/fastserializer.cxx b/sax/source/tools/fastserializer.cxx
index 10e7ab39f174..a2ba5c15f38f 100644
--- a/sax/source/tools/fastserializer.cxx
+++ b/sax/source/tools/fastserializer.cxx
@@ -196,7 +196,10 @@ namespace sax_fastparser {
}
#ifdef DBG_UTIL
- m_DebugStartedElements.push(Element);
+ if (mbMarkStackEmpty)
+ m_DebugStartedElements.push(Element);
+ else
+ maMarkStack.top()->m_DebugStartedElements.push_back(Element);
#endif
writeBytes(sOpeningBracket, N_CHARS(sOpeningBracket));
@@ -213,10 +216,30 @@ namespace sax_fastparser {
void FastSaxSerializer::endFastElement( ::sal_Int32 Element )
{
#ifdef DBG_UTIL
- assert(!m_DebugStartedElements.empty());
// Well-formedness constraint: Element Type Match
- assert(Element == m_DebugStartedElements.top());
- m_DebugStartedElements.pop();
+ if (mbMarkStackEmpty)
+ {
+ assert(!m_DebugStartedElements.empty());
+ assert(Element == m_DebugStartedElements.top());
+ m_DebugStartedElements.pop();
+ }
+ else
+ {
+ if (dynamic_cast<ForSort*>(maMarkStack.top().get()))
+ {
+ // Sort is always well-formed fragment
+ assert(!maMarkStack.top()->m_DebugStartedElements.empty());
+ }
+ if (maMarkStack.top()->m_DebugStartedElements.empty())
+ {
+ maMarkStack.top()->m_DebugEndedElements.push_back(Element);
+ }
+ else
+ {
+ assert(Element == maMarkStack.top()->m_DebugStartedElements.back());
+ maMarkStack.top()->m_DebugStartedElements.pop_back();
+ }
+ }
#endif
writeBytes(sOpeningBracketAndSlash, N_CHARS(sOpeningBracketAndSlash));
@@ -324,17 +347,98 @@ namespace sax_fastparser {
mbMarkStackEmpty = false;
}
+#ifdef DBG_UTIL
+ static void lcl_DebugMergeAppend(
+ std::deque<sal_Int32> & rLeftEndedElements,
+ std::deque<sal_Int32> & rLeftStartedElements,
+ std::deque<sal_Int32> & rRightEndedElements,
+ std::deque<sal_Int32> & rRightStartedElements)
+ {
+ while (!rRightEndedElements.empty())
+ {
+ if (rLeftStartedElements.empty())
+ {
+ rLeftEndedElements.push_back(rRightEndedElements.front());
+ }
+ else
+ {
+ assert(rLeftStartedElements.back() == rRightEndedElements.front());
+ rLeftStartedElements.pop_back();
+ }
+ rRightEndedElements.pop_front();
+ }
+ while (!rRightStartedElements.empty())
+ {
+ rLeftStartedElements.push_back(rRightStartedElements.front());
+ rRightStartedElements.pop_front();
+ }
+ }
+
+ static void lcl_DebugMergePrepend(
+ std::deque<sal_Int32> & rLeftEndedElements,
+ std::deque<sal_Int32> & rLeftStartedElements,
+ std::deque<sal_Int32> & rRightEndedElements,
+ std::deque<sal_Int32> & rRightStartedElements)
+ {
+ while (!rLeftStartedElements.empty())
+ {
+ if (rRightEndedElements.empty())
+ {
+ rRightStartedElements.push_front(rLeftStartedElements.back());
+ }
+ else
+ {
+ assert(rRightEndedElements.front() == rLeftStartedElements.back());
+ rRightEndedElements.pop_front();
+ }
+ rLeftStartedElements.pop_back();
+ }
+ while (!rLeftEndedElements.empty())
+ {
+ rRightEndedElements.push_front(rLeftEndedElements.back());
+ rLeftEndedElements.pop_back();
+ }
+ }
+#endif
+
void FastSaxSerializer::mergeTopMarks( sax_fastparser::MergeMarksEnum eMergeType )
{
SAL_WARN_IF(mbMarkStackEmpty, "sax", "Empty mark stack - nothing to merge");
if ( mbMarkStackEmpty )
return;
+#ifdef DBG_UTIL
+ if (dynamic_cast<ForSort*>(maMarkStack.top().get()))
+ {
+ // Sort is always well-formed fragment
+ assert(maMarkStack.top()->m_DebugStartedElements.empty());
+ assert(maMarkStack.top()->m_DebugEndedElements.empty());
+ }
+ lcl_DebugMergeAppend(
+ maMarkStack.top()->m_DebugEndedElements,
+ maMarkStack.top()->m_DebugStartedElements,
+ maMarkStack.top()->m_DebugPostponedEndedElements,
+ maMarkStack.top()->m_DebugPostponedStartedElements);
+#endif
+
// flush, so that we get everything in getData()
maCachedOutputStream.flush();
if ( maMarkStack.size() == 1 && eMergeType != MERGE_MARKS_IGNORE)
{
+#if DBG_UTIL
+ while (!maMarkStack.top()->m_DebugEndedElements.empty())
+ {
+ assert(maMarkStack.top()->m_DebugEndedElements.front() == m_DebugStartedElements.top());
+ maMarkStack.top()->m_DebugEndedElements.pop_front();
+ m_DebugStartedElements.pop();
+ }
+ while (!maMarkStack.top()->m_DebugStartedElements.empty())
+ {
+ m_DebugStartedElements.push(maMarkStack.top()->m_DebugStartedElements.front());
+ maMarkStack.top()->m_DebugStartedElements.pop_front();
+ }
+#endif
Sequence<sal_Int8> aSeq( maMarkStack.top()->getData() );
maMarkStack.pop();
mbMarkStackEmpty = true;
@@ -343,8 +447,51 @@ namespace sax_fastparser {
return;
}
+#if DBG_UTIL
+ ::std::deque<sal_Int32> topDebugStartedElements(maMarkStack.top()->m_DebugStartedElements);
+ ::std::deque<sal_Int32> topDebugEndedElements(maMarkStack.top()->m_DebugEndedElements);
+#endif
const Int8Sequence aMerge( maMarkStack.top()->getData() );
maMarkStack.pop();
+#if DBG_UTIL
+ switch (eMergeType)
+ {
+ case MERGE_MARKS_APPEND:
+ lcl_DebugMergeAppend(
+ maMarkStack.top()->m_DebugEndedElements,
+ maMarkStack.top()->m_DebugStartedElements,
+ topDebugEndedElements,
+ topDebugStartedElements);
+ break;
+ case MERGE_MARKS_PREPEND:
+ if (dynamic_cast<ForSort*>(maMarkStack.top().get())) // argh...
+ {
+ lcl_DebugMergeAppend(
+ maMarkStack.top()->m_DebugEndedElements,
+ maMarkStack.top()->m_DebugStartedElements,
+ topDebugEndedElements,
+ topDebugStartedElements);
+ }
+ else
+ {
+ lcl_DebugMergePrepend(
+ topDebugEndedElements,
+ topDebugStartedElements,
+ maMarkStack.top()->m_DebugEndedElements,
+ maMarkStack.top()->m_DebugStartedElements);
+ }
+ break;
+ case MERGE_MARKS_POSTPONE:
+ lcl_DebugMergeAppend(
+ maMarkStack.top()->m_DebugPostponedEndedElements,
+ maMarkStack.top()->m_DebugPostponedStartedElements,
+ topDebugEndedElements,
+ topDebugStartedElements);
+ break;
+ case MERGE_MARKS_IGNORE:
+ break;
+ }
+#endif
if (maMarkStack.empty())
{
mbMarkStackEmpty = true;
diff --git a/sax/source/tools/fastserializer.hxx b/sax/source/tools/fastserializer.hxx
index 95e631c355d2..4dc786b7a712 100644
--- a/sax/source/tools/fastserializer.hxx
+++ b/sax/source/tools/fastserializer.hxx
@@ -161,6 +161,15 @@ private:
Int8Sequence maPostponed;
public:
+#ifdef DBG_UTIL
+ // pending close tags, followed by pending open tags
+ ::std::deque<sal_Int32> m_DebugEndedElements;
+ ::std::deque<sal_Int32> m_DebugStartedElements;
+ // ... and another buffer for maPostponed ...
+ ::std::deque<sal_Int32> m_DebugPostponedEndedElements;
+ ::std::deque<sal_Int32> m_DebugPostponedStartedElements;
+#endif
+
ForMerge() : maData(), maPostponed() {}
virtual ~ForMerge() {}