summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/parser/stack/Stack.cpp57
-rw-r--r--src/core/parser/stack/Stack.hpp7
-rw-r--r--src/formats/osxml/OsxmlEventParser.cpp2
-rw-r--r--test/core/parser/stack/StackTest.cpp115
4 files changed, 141 insertions, 40 deletions
diff --git a/src/core/parser/stack/Stack.cpp b/src/core/parser/stack/Stack.cpp
index b98cddb..07f7d8c 100644
--- a/src/core/parser/stack/Stack.cpp
+++ b/src/core/parser/stack/Stack.cpp
@@ -74,12 +74,12 @@ void HandlerInfo::fieldStart(bool isDefault, bool isImplicit, bool isValid)
inDefaultField = isDefault || isImplicit;
inImplicitDefaultField = isImplicit;
inValidField = isValid;
- hadDefaultField = hadDefaultField || inDefaultField;
fieldIdx++;
}
void HandlerInfo::fieldEnd()
{
+ hadDefaultField = hadDefaultField || inDefaultField;
inField = false;
inDefaultField = false;
inImplicitDefaultField = false;
@@ -269,6 +269,22 @@ void Stack::endCurrentHandler()
}
}
+void Stack::endOverdueHandlers()
+{
+ if (!stack.empty()) {
+ // Fetch the handler info for the current top-level element
+ HandlerInfo &info = stack.back();
+
+ // Abort if this handler currently is inside a field
+ if (info.inField || !info.hadDefaultField) {
+ return;
+ }
+
+ // Otherwise end the current handler
+ endCurrentHandler();
+ }
+}
+
bool Stack::ensureHandlerIsInField()
{
// If the current handler is not in a field (and actually has a handler)
@@ -308,6 +324,10 @@ Logger &Stack::logger() { return ctx.getLogger(); }
void Stack::command(const Variant &name, const Variant::mapType &args)
{
+ // End handlers that already had a default field and are currently not
+ // active.
+ endOverdueHandlers();
+
// Make sure the given identifier is valid (preventing "*" from being
// malicously passed to this function)
if (!Utils::isNamespacedIdentifier(name.asString())) {
@@ -396,6 +416,10 @@ void Stack::command(const Variant &name, const Variant::mapType &args)
void Stack::data(const Variant &data)
{
+ // End handlers that already had a default field and are currently not
+ // active.
+ endOverdueHandlers();
+
while (true) {
// Check whether there is any command the data can be sent to
if (stack.empty()) {
@@ -414,7 +438,11 @@ void Stack::data(const Variant &data)
// If this field should not get any data, log an error and do not call
// the "data" handler
if (!info.inValidField) {
- logger().error("Did not expect any data here", data);
+ // If the "hadDefaultField" flag is set, we already issued an error
+ // message
+ if (!info.hadDefaultField) {
+ logger().error("Did not expect any data here", data);
+ }
}
if (handlersValid() && info.inValidField) {
@@ -472,13 +500,24 @@ void Stack::fieldStart(bool isDefault)
return;
}
+ // If the handler already had a default field we cannot start a new field
+ // (the default field always is the last field) -- mark the command as
+ // invalid
+ if (info.hadDefaultField) {
+ logger().error(
+ std::string("Got field start, but command \"") +
+ currentCommandName() +
+ std::string("\" does not have any more fields"));
+ }
+
// Copy the isDefault flag to a local variable, the fieldStart method will
// write into this variable
bool defaultField = isDefault;
// Do not call the "fieldStart" function if we're in an invalid subtree
+ // or the handler already had a default field
bool valid = false;
- if (handlersValid()) {
+ if (handlersValid() && !info.hadDefaultField) {
try {
valid = info.handler->fieldStart(defaultField, info.fieldIdx);
}
@@ -499,11 +538,6 @@ void Stack::fieldStart(bool isDefault)
void Stack::fieldEnd()
{
- // Check whether there is any command the data can be sent to
- if (stack.empty()) {
- throw LoggableException("No command, but got end of field.");
- }
-
// Unroll the stack until the next explicitly open field
while (!stack.empty()) {
HandlerInfo &info = currentInfo();
@@ -524,7 +558,7 @@ void Stack::fieldEnd()
// Only continue if the current handler stack is in a valid state, do not
// call the fieldEnd function if something went wrong before
- if (handlersValid()) {
+ if (handlersValid() && !info.hadDefaultField) {
try {
info.handler->fieldEnd();
}
@@ -535,11 +569,6 @@ void Stack::fieldEnd()
// This command no longer is in a field
info.fieldEnd();
-
- // As soon as this command had a default field, remove it from the stack
- if (info.hadDefaultField) {
- endCurrentHandler();
- }
}
void Stack::annotationStart(const Variant &className, const Variant &args)
diff --git a/src/core/parser/stack/Stack.hpp b/src/core/parser/stack/Stack.hpp
index 76eefd9..b67ce82 100644
--- a/src/core/parser/stack/Stack.hpp
+++ b/src/core/parser/stack/Stack.hpp
@@ -220,6 +220,13 @@ private:
HandlerInfo &lastInfo();
/**
+ * Ends all handlers that currently are not inside a field and already had
+ * a default field. This method is called whenever the data() and command()
+ * events are reached.
+ */
+ void endOverdueHandlers();
+
+ /**
* Ends the current handler and removes the corresponding element from the
* stack.
*/
diff --git a/src/formats/osxml/OsxmlEventParser.cpp b/src/formats/osxml/OsxmlEventParser.cpp
index 7404960..788f376 100644
--- a/src/formats/osxml/OsxmlEventParser.cpp
+++ b/src/formats/osxml/OsxmlEventParser.cpp
@@ -476,7 +476,7 @@ OsxmlEventParser::OsxmlEventParser(CharReader &reader, OsxmlEvents &events,
: reader(reader),
events(events),
logger(logger),
- whitespaceMode(WhitespaceMode::TRIM),
+ whitespaceMode(WhitespaceMode::COLLAPSE),
data(new OsxmlEventParserData())
{
}
diff --git a/test/core/parser/stack/StackTest.cpp b/test/core/parser/stack/StackTest.cpp
index 59fdd59..e25f487 100644
--- a/test/core/parser/stack/StackTest.cpp
+++ b/test/core/parser/stack/StackTest.cpp
@@ -230,30 +230,34 @@ TEST(Stack, basicTest)
EXPECT_EQ(&States::BodyChildren, &s.currentState());
s.fieldEnd();
- tracker.expect(3, 1, 3, 1, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(3, 0, 3, 1, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
s.fieldEnd();
- EXPECT_EQ("document", s.currentCommandName());
- EXPECT_EQ(&States::Document, &s.currentState());
- tracker.expect(3, 2, 3, 2, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
+ EXPECT_EQ("body", s.currentCommandName());
+ EXPECT_EQ(&States::Body, &s.currentState());
+ tracker.expect(3, 1, 3, 2, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
s.command("body", {});
+ EXPECT_EQ("body", s.currentCommandName());
+ EXPECT_EQ(&States::Body, &s.currentState());
+ tracker.expect(4, 2, 3, 2, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
s.fieldStart(true);
s.data("test3");
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
s.fieldEnd();
- tracker.expect(4, 3, 4, 3, 0, 0, 3); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(4, 2, 4, 3, 0, 0, 3); // sc, ec, fsc, fse, asc, aec, dc
- EXPECT_EQ("document", s.currentCommandName());
- EXPECT_EQ(&States::Document, &s.currentState());
+ EXPECT_EQ("body", s.currentCommandName());
+ EXPECT_EQ(&States::Body, &s.currentState());
s.fieldEnd();
- tracker.expect(4, 4, 4, 4, 0, 0, 3); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(4, 3, 4, 4, 0, 0, 3); // sc, ec, fsc, fse, asc, aec, dc
- EXPECT_EQ("", s.currentCommandName());
- EXPECT_EQ(&States::None, &s.currentState());
+ EXPECT_EQ("document", s.currentCommandName());
+ EXPECT_EQ(&States::Document, &s.currentState());
}
+ tracker.expect(4, 4, 4, 4, 0, 0, 3); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_FALSE(logger.hasError());
}
@@ -273,9 +277,13 @@ TEST(Stack, errorInvalidCommands)
s.fieldEnd();
s.fieldEnd();
s.fieldEnd();
+
+ logger.reset();
+ s.fieldEnd();
+ ASSERT_TRUE(logger.hasError());
+
+ EXPECT_THROW(s.data("test"), LoggableException);
EXPECT_EQ(&States::None, &s.currentState());
- ASSERT_THROW(s.fieldEnd(), LoggableException);
- ASSERT_THROW(s.data("test"), LoggableException);
}
TEST(Stack, validation)
@@ -304,27 +312,34 @@ TEST(Stack, validation)
TEST(Stack, invalidCommandName)
{
- Stack s{env.context, States::AnyHandlers};
tracker.reset();
logger.reset();
+ Stack s{env.context, States::AnyHandlers};
s.command("a", {});
+ tracker.expect(1, 0, 0, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
s.fieldStart(true);
s.fieldEnd();
- tracker.expect(1, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(1, 0, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
s.command("a_", {});
+ tracker.expect(2, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
s.fieldStart(true);
s.fieldEnd();
- tracker.expect(2, 2, 2, 2, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(2, 1, 2, 2, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
s.command("a_:b", {});
+ tracker.expect(3, 2, 2, 2, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
s.fieldStart(true);
s.fieldEnd();
- tracker.expect(3, 3, 3, 3, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(3, 2, 3, 3, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_THROW(s.command("_a", {}), LoggableException);
+ tracker.expect(3, 3, 3, 3, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+
ASSERT_THROW(s.command("a:", {}), LoggableException);
+ tracker.expect(3, 3, 3, 3, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+
ASSERT_THROW(s.command("a:_b", {}), LoggableException);
tracker.expect(3, 3, 3, 3, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
}
@@ -375,8 +390,9 @@ TEST(Stack, multipleFields)
EXPECT_EQ("test3", tracker.dataData);
s.fieldEnd();
- tracker.expect(1, 1, 3, 3, 0, 0, 3); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(1, 0, 3, 3, 0, 0, 3); // sc, ec, fsc, fse, asc, aec, dc
}
+ tracker.expect(1, 1, 3, 3, 0, 0, 3); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_FALSE(logger.hasError());
}
@@ -413,8 +429,8 @@ TEST(Stack, implicitDefaultFieldOnNewCommandWithExplicitDefaultField)
ASSERT_EQ("b", s.currentCommandName());
s.fieldStart(true);
s.fieldEnd();
- tracker.expect(2, 1, 2, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
- ASSERT_EQ("a", s.currentCommandName());
+ tracker.expect(2, 0, 2, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ ASSERT_EQ("b", s.currentCommandName());
}
tracker.expect(2, 2, 2, 2, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_FALSE(logger.hasError());
@@ -454,8 +470,8 @@ TEST(Stack, noImplicitDefaultFieldIfDefaultFieldGiven)
tracker.expect(1, 0, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_EQ("a", s.currentCommandName());
s.fieldEnd();
- tracker.expect(1, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
- ASSERT_EQ("", s.currentCommandName());
+ tracker.expect(1, 0, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ ASSERT_EQ("a", s.currentCommandName());
s.command("b", {});
tracker.expect(2, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
@@ -530,7 +546,7 @@ TEST(Stack, autoImplicitFieldEnd)
s.command("e", {});
s.fieldStart(true);
s.fieldEnd();
- tracker.expect(5, 1, 5, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(5, 0, 5, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
}
tracker.expect(5, 5, 5, 5, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_FALSE(logger.hasError());
@@ -547,7 +563,7 @@ TEST(Stack, invalidDefaultField)
tracker.fieldStartResult = false;
s.fieldStart(true);
s.fieldEnd();
- tracker.expect(1, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(1, 0, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
}
tracker.expect(1, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_FALSE(logger.hasError());
@@ -567,7 +583,7 @@ TEST(Stack, errorInvalidDefaultFieldData)
s.data("test");
ASSERT_TRUE(logger.hasError());
s.fieldEnd();
- tracker.expect(1, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(1, 0, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
}
tracker.expect(1, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
}
@@ -674,8 +690,57 @@ TEST(Stack, fieldEndWhenImplicitDefaultFieldOpen)
s.command("b", {});
s.data("test");
s.fieldEnd();
- tracker.expect(2, 2, 2, 2, 0, 0, 1); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(2, 1, 2, 2, 0, 0, 1); // sc, ec, fsc, fse, asc, aec, dc
+ }
+ tracker.expect(2, 2, 2, 2, 0, 0, 1); // sc, ec, fsc, fse, asc, aec, dc
+ ASSERT_FALSE(logger.hasError());
+}
+
+TEST(Stack, fieldAfterDefaultField)
+{
+ tracker.reset();
+ logger.reset();
+
+ {
+ Stack s{env.context, States::AnyHandlers};
+ s.command("a", {});
+ tracker.expect(1, 0, 0, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ s.fieldStart(true);
+ tracker.expect(1, 0, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+
+ s.command("b", {});
+ tracker.expect(2, 0, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+
+ s.fieldStart(false);
+ tracker.expect(2, 0, 2, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ s.data("f1");
+ tracker.expect(2, 0, 2, 0, 0, 0, 1); // sc, ec, fsc, fse, asc, aec, dc
+ s.fieldEnd();
+ tracker.expect(2, 0, 2, 1, 0, 0, 1); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.fieldStartSetIsDefault = true;
+
+ s.fieldStart(false);
+ tracker.fieldStartSetIsDefault = false;
+ tracker.expect(2, 0, 3, 1, 0, 0, 1); // sc, ec, fsc, fse, asc, aec, dc
+ s.data("f2");
+ tracker.expect(2, 0, 3, 1, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
+ s.fieldEnd();
+ tracker.expect(2, 0, 3, 2, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
+
+ ASSERT_FALSE(logger.hasError());
+ s.fieldStart(false);
+ ASSERT_TRUE(logger.hasError());
+ logger.reset();
+ tracker.expect(2, 0, 3, 2, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
+ s.data("f3");
+ tracker.expect(2, 0, 3, 2, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
+ s.fieldEnd();
+ tracker.expect(2, 0, 3, 2, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
+
+ s.fieldEnd();
+ tracker.expect(2, 1, 3, 3, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
}
+ tracker.expect(2, 2, 3, 3, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_FALSE(logger.hasError());
}