diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/String.cpp | 9 | ||||
-rw-r--r-- | src/common/StringUtil.cpp | 4 | ||||
-rw-r--r-- | src/xml/XmlNode.cpp | 6 | ||||
-rw-r--r-- | src/xml/XmlParser.cpp | 115 |
4 files changed, 110 insertions, 24 deletions
diff --git a/src/common/String.cpp b/src/common/String.cpp index 743a33fd..8d674369 100644 --- a/src/common/String.cpp +++ b/src/common/String.cpp @@ -211,6 +211,15 @@ String::iterator String::erase(const_iterator start, const_iterator end) { return s; } +String& String::TrimEnd() { + if (size_ == 0) return *this; + while (size_ > 0 && IsWhitespace(buffer_[size_ - 1])) { + size_--; + } + + return *this; +} + std::string String::ToUtf8() const { return cru::ToUtf8(buffer_, size_); } void String::AppendCodePoint(CodePoint code_point) { diff --git a/src/common/StringUtil.cpp b/src/common/StringUtil.cpp index c828fa21..d3948c6a 100644 --- a/src/common/StringUtil.cpp +++ b/src/common/StringUtil.cpp @@ -252,4 +252,8 @@ char16_t ToUpper(char16_t c) { } return c; } + +char16_t IsWhitespace(char16_t c) { + return c == u' ' || c == u'\t' || c == u'\n' || c == u'\r'; +} } // namespace cru diff --git a/src/xml/XmlNode.cpp b/src/xml/XmlNode.cpp index f4b43ea6..d6203973 100644 --- a/src/xml/XmlNode.cpp +++ b/src/xml/XmlNode.cpp @@ -1,6 +1,12 @@ #include "cru/xml/XmlNode.hpp" namespace cru::xml { +XmlElementNode::~XmlElementNode() { + for (auto child : children_) { + delete child; + } +} + void XmlElementNode::AddAttribute(String key, String value) { attributes_[std::move(key)] = std::move(value); } diff --git a/src/xml/XmlParser.cpp b/src/xml/XmlParser.cpp index f24a7f68..d0f61542 100644 --- a/src/xml/XmlParser.cpp +++ b/src/xml/XmlParser.cpp @@ -2,6 +2,10 @@ #include "cru/xml/XmlNode.hpp" namespace cru::xml { +XmlParser::XmlParser(String xml) : xml_(std::move(xml)) {} + +XmlParser::~XmlParser() { delete pseudo_root_node_; } + XmlElementNode* XmlParser::Parse() { if (!cache_) { cache_ = DoParse(); @@ -16,6 +20,13 @@ char16_t XmlParser::Read1() { return xml_[current_position_++]; } +String XmlParser::ReadWithoutAdvance(int count) { + if (current_position_ + count > xml_.size()) { + return u""; + } + return xml_.substr(current_position_, count); +} + void XmlParser::ReadSpacesAndDiscard() { while (current_position_ < xml_.size() && (xml_[current_position_] == ' ' || xml_[current_position_] == '\t' || @@ -70,48 +81,104 @@ String XmlParser::ReadAttributeString() { XmlElementNode* XmlParser::DoParse() { while (current_position_ < xml_.size()) { - switch (xml_[current_position_]) { - case '<': { - ++current_position_; + ReadSpacesAndDiscard(); - if (Read1() == '/') { - } else { - ReadSpacesAndDiscard(); + if (current_position_ == xml_.size()) { + break; + } - String tag = ReadIdenitifier(); + if (ReadWithoutAdvance() == u"<") { + current_position_ += 1; - XmlElementNode* node = new XmlElementNode(tag); + if (ReadWithoutAdvance() == u"/") { + current_position_ += 1; - while (true) { - ReadSpacesAndDiscard(); - if (Read1() == '>') { - break; - } else { - String attribute_name = ReadIdenitifier(); + ReadSpacesAndDiscard(); + + String tag = ReadIdenitifier(); + + if (tag != current_->GetTag()) { + throw XmlParsingException(u"Tag mismatch."); + } + + ReadSpacesAndDiscard(); + + if (Read1() != '>') { + throw XmlParsingException(u"Expected >."); + } + + current_ = current_->GetParent(); + } else { + ReadSpacesAndDiscard(); + + String tag = ReadIdenitifier(); + + XmlElementNode* node = new XmlElementNode(tag); - ReadSpacesAndDiscard(); + bool is_self_closing = false; - if (Read1() != '=') { - throw XmlParsingException(u"Expected '='"); - } + while (true) { + ReadSpacesAndDiscard(); + auto c = ReadWithoutAdvance(); + if (c == u">") { + current_position_ += 1; + break; + } else if (c == u"/") { + current_position_ += 1; + + if (Read1() != '>') { + throw XmlParsingException(u"Expected >."); + } - ReadSpacesAndDiscard(); + is_self_closing = true; + break; + } else { + String attribute_name = ReadIdenitifier(); - String attribute_value = ReadAttributeString(); + ReadSpacesAndDiscard(); - node->AddAttribute(attribute_name, attribute_value); + if (Read1() != '=') { + throw XmlParsingException(u"Expected '='"); } + + ReadSpacesAndDiscard(); + + String attribute_value = ReadAttributeString(); + + node->AddAttribute(attribute_name, attribute_value); } + } + + current_->AddChild(node); - current_->AddChild(node); + if (!is_self_closing) { current_ = node; } + } + + } else { + String text; + + while (ReadWithoutAdvance() != u"<") { + char16_t c = Read1(); - break; + text += c; } + + if (!text.empty()) current_->AddChild(new XmlTextNode(text.TrimEnd())); } } - return pseudo_root_node_; + if (current_ != pseudo_root_node_) { + throw XmlParsingException(u"Unexpected end of xml"); + } + + if (pseudo_root_node_->GetChildren().size() != 1 || + pseudo_root_node_->GetChildren()[0]->GetType() != + XmlNode::Type::Element) { + throw XmlParsingException(u"Expected 1 element node as root."); + } + + return static_cast<XmlElementNode*>(pseudo_root_node_->GetChildren()[0]); } } // namespace cru::xml |