Move xml and svg to lower levels.

This commit is contained in:
jmsgrogan 2023-01-18 10:55:32 +00:00
parent 942cc2539c
commit 7cab70f839
32 changed files with 35 additions and 33 deletions

View file

@ -24,6 +24,12 @@ list(APPEND HEADERS
http/HttpRequest.h
serializers/TomlReader.h
Win32BaseIncludes.h
xml/XmlParser.h
xml/XmlDocument.h
xml/XmlWriter.h
xml/xml-elements/XmlElement.h
xml/xml-elements/XmlAttribute.h
xml/xml-elements/XmlProlog.h
)
list(APPEND SOURCES
@ -51,7 +57,14 @@ list(APPEND SOURCES
http/HttpResponse.cpp
http/HttpHeader.cpp
http/HttpRequest.cpp
serializers/TomlReader.cpp)
serializers/TomlReader.cpp
xml/XmlParser.cpp
xml/XmlDocument.cpp
xml/XmlWriter.cpp
xml/xml-elements/XmlElement.cpp
xml/xml-elements/XmlAttribute.cpp
xml/xml-elements/XmlProlog.cpp
)
add_library(${MODULE_NAME} SHARED ${SOURCES} ${HEADERS})
@ -65,6 +78,8 @@ target_include_directories(${MODULE_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/http
${CMAKE_CURRENT_SOURCE_DIR}/data_structures
${CMAKE_CURRENT_SOURCE_DIR}/serializers
${CMAKE_CURRENT_SOURCE_DIR}/xml
${CMAKE_CURRENT_SOURCE_DIR}/xml/xml-elements
)
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/base)

View file

@ -0,0 +1,43 @@
#include "XmlDocument.h"
#include "XmlProlog.h"
#include "XmlElement.h"
#include <iostream>
XmlDocument::XmlDocument()
:mProlog(XmlProlog::Create("xml"))
{
}
XmlDocument::~XmlDocument()
{
}
XmlDocumentPtr XmlDocument::Create()
{
return std::make_unique<XmlDocument>();
}
void XmlDocument::setProlog(XmlPrologPtr prolog)
{
mProlog = std::move(prolog);
}
XmlProlog* XmlDocument::getProlog() const
{
return mProlog.get();
}
void XmlDocument::setRoot(XmlElementPtr root)
{
mRoot = std::move(root);
}
XmlElement* XmlDocument::getRoot() const
{
return mRoot.get();
}

View file

@ -0,0 +1,31 @@
#pragma once
#include <memory>
#include <string>
#include "XmlElement.h"
#include "XmlProlog.h"
class XmlElement;
class XmlProlog;
using XmlPrologPtr = std::unique_ptr<XmlProlog>;
using XmlElementPtr = std::unique_ptr<XmlElement>;
class XmlDocument
{
public:
XmlDocument();
virtual ~XmlDocument();
static std::unique_ptr<XmlDocument> Create();
XmlProlog* getProlog() const;
XmlElement* getRoot() const;
void setProlog(XmlPrologPtr prolog);
void setRoot(XmlElementPtr root);
private:
XmlPrologPtr mProlog;
XmlElementPtr mRoot;
};
using XmlDocumentPtr = std::unique_ptr<XmlDocument>;

View file

@ -0,0 +1,409 @@
#include "XmlParser.h"
#include "StringUtils.h"
#include "XmlDocument.h"
#include "XmlElement.h"
#include "XmlAttribute.h"
#include <iostream>
using LS = XmlParser::LineState;
using DS = XmlParser::DocumentState;
XmlParser::XmlParser()
: mDocument(XmlDocument::Create()),
mDocumentState(XmlParser::DocumentState::Await_Prolog),
mLineState(XmlParser::LineState::Await_Tag_Open),
mWorkingElements()
{
}
void XmlParser::processLine(const std::string& input)
{
for (std::size_t idx=0; idx<input.size(); idx++)
{
switch (input[idx])
{
case StringUtils::LEFT_BRACKET:
onLeftBracket();
break;
case StringUtils::RIGHT_BRACKET:
onRightBracket();
break;
case StringUtils::QUESTION_MARK:
onQuestionMark();
break;
case StringUtils::FORWARD_SLASH:
onForwardSlash();
break;
case StringUtils::EQUALS:
onEquals();
break;
case StringUtils::DOUBLE_QUOTE:
onDoubleQuote();
break;
default:
onChar(input[idx]);
break;
}
}
}
void XmlParser::onChar(char c)
{
if(StringUtils::isAlphaNumeric(c))
{
onAlphaNumeric(c);
}
else if(StringUtils::isSpace(c))
{
onSpace(c);
}
else
{
onNonAlphaNumeric(c);
}
}
void XmlParser::onAlphaNumeric(char c)
{
switch(mLineState)
{
case LS::Await_Tag_Open:
onTextStart(c);
break;
case LS::Await_Tag_Follower:
case LS::Await_Tag_Name:
{
onTagNameStart(c);
break;
}
case LS::Await_Tag_Name_End:
{
mWorkingTagName.push_back(c);
break;
}
case LS::Await_Attribute_Name:
{
onAttributeNameStart(c);
break;
}
case LS::Await_Attribute_Name_End:
{
mWorkingAttributeName.push_back(c);
break;
}
case LS::Await_Attribute_Value:
{
break;
}
case LS::Await_Attribute_Value_End:
{
mWorkingAttributeValue.push_back(c);
break;
}
case LS::Await_Text_End:
{
mWorkingText.push_back(c);
break;
}
default:
break;
}
}
void XmlParser::onNonAlphaNumeric(char c)
{
switch(mLineState)
{
case LS::Await_Tag_Name_End:
{
mWorkingTagName.push_back(c);
break;
}
case LS::Await_Attribute_Name_End:
{
mWorkingAttributeName.push_back(c);
break;
}
case LS::Await_Attribute_Value_End:
{
mWorkingAttributeValue.push_back(c);
break;
}
case LS::Await_Text_End:
{
mWorkingText.push_back(c);
break;
}
default:
break;
}
}
void XmlParser::onSpace(char c)
{
switch(mLineState)
{
case LS::Await_Tag_Name_End:
onTagNameEnd();
break;
case LS::Await_Attribute_Name_End:
onAttributeNameEnd();
break;
case LS::Await_Text_End:
mWorkingText.push_back(c);
break;
case LS::Await_Attribute_Value_End:
mWorkingAttributeValue.push_back(c);
break;
default:
break;
}
}
void XmlParser::onLeftBracket()
{
switch(mLineState)
{
case LS::Await_Tag_Open:
{
onTagOpen();
break;
}
case LS::Await_Text_End:
{
onTextEnd();
onTagOpen();
break;
}
default:
onNonAlphaNumeric(StringUtils::LEFT_BRACKET);
break;
}
}
void XmlParser::onRightBracket()
{
switch(mLineState)
{
case LS::Await_Tag_Name_End:
case LS::Await_Attribute_Name:
case LS::Await_Attribute_Name_End:
case LS::Await_Attribute_Value:
case LS::Await_Tag_Inline_Close:
{
onTagClose();
break;
}
default:
onNonAlphaNumeric(StringUtils::RIGHT_BRACKET);
break;
}
}
void XmlParser::onQuestionMark()
{
if(mLineState == LS::Await_Tag_Follower)
{
if(mDocumentState == DS::Await_Prolog)
{
onStartProlog();
}
}
else if(mDocumentState != DS::Build_Prolog)
{
onNonAlphaNumeric(StringUtils::QUESTION_MARK);
}
}
void XmlParser::onForwardSlash()
{
if (mLineState == LS::Await_Tag_Follower)
{
if (mDocumentState == DS::Await_Element || mDocumentState == DS::Build_Element)
{
mDocumentState = DS::Close_Element;
}
}
else if(mLineState == LS::Await_Attribute_Name)
{
mLineState = LS::Await_Tag_Inline_Close;
}
else
{
onNonAlphaNumeric(StringUtils::FORWARD_SLASH);
}
}
void XmlParser::onEquals()
{
if(mLineState == LS::Await_Attribute_Name_End)
{
onAttributeNameEnd();
}
else
{
onNonAlphaNumeric(StringUtils::EQUALS);
}
}
void XmlParser::onDoubleQuote()
{
if(mLineState == LS::Await_Attribute_Value)
{
onAttributeValueStart();
}
else if(mLineState == LS::Await_Attribute_Value_End)
{
onAttributeValueEnd();
}
}
void XmlParser::onTagOpen()
{
mLineState = LS::Await_Tag_Follower;
}
void XmlParser::onTagClose()
{
if(mDocumentState == DS::Build_Prolog)
{
onFinishProlog();
}
else if(mDocumentState == DS::Build_Element)
{
if(mLineState == LS::Await_Tag_Name_End)
{
onTagNameEnd();
}
else if (mLineState == LS::Await_Tag_Inline_Close)
{
if (!mWorkingElements.empty())
{
mWorkingElements.pop();
}
}
onElementTagEnd();
}
else if(mDocumentState == DS::Close_Element)
{
mDocumentState = DS::Await_Element;
mLineState = LS::Await_Tag_Open;
if (!mWorkingElements.empty())
{
mWorkingElements.pop();
}
}
}
void XmlParser::onTextStart(char c)
{
mWorkingText = c;
mLineState = LS::Await_Text_End;
}
void XmlParser::onTextEnd()
{
mWorkingElements.top()->setText(mWorkingText);
}
void XmlParser::onElementTagEnd()
{
mDocumentState = DS::Await_Element;
mLineState = LS::Await_Tag_Open;
}
void XmlParser::onTagNameStart(char c)
{
mWorkingTagName = c;
mLineState = LS::Await_Tag_Name_End;
if(mDocumentState != DS::Build_Prolog && mDocumentState != DS::Close_Element)
{
mDocumentState = DS::Build_Element;
}
}
void XmlParser::onTagNameEnd()
{
if(mDocumentState == DS::Build_Prolog)
{
mDocument->getProlog()->setTagName(mWorkingTagName);
mLineState = LS::Await_Attribute_Name;
}
else if(mDocumentState == DS::Build_Element)
{
auto new_element = XmlElement::Create(mWorkingTagName);
auto working_element = new_element.get();
if (!mDocument->getRoot())
{
mDocument->setRoot(std::move(new_element));
}
else
{
mWorkingElements.top()->addChild(std::move(new_element));
}
mWorkingElements.push(working_element);
mLineState = LS::Await_Attribute_Name;
}
}
void XmlParser::onAttributeNameStart(char c)
{
mWorkingAttributeName = c;
mLineState = LS::Await_Attribute_Name_End;
}
void XmlParser::onAttributeNameEnd()
{
auto attribute = XmlAttribute::Create(mWorkingAttributeName);
if(mDocumentState == DS::Build_Prolog)
{
mDocument->getProlog()->addAttribute(std::move(attribute));
}
else if(mDocumentState == DS::Build_Element)
{
mWorkingElements.top()->addAttribute(std::move(attribute));
}
mLineState = LS::Await_Attribute_Value;
}
void XmlParser::onAttributeValueStart()
{
mWorkingAttributeValue = "";
mLineState = LS::Await_Attribute_Value_End;
}
void XmlParser::onAttributeValueEnd()
{
if(mDocumentState == DS::Build_Prolog)
{
mDocument->getProlog()->getAttribute(mWorkingAttributeName)->setValue(mWorkingAttributeValue);
}
else if(mDocumentState == DS::Build_Element)
{
mWorkingElements.top()->getAttribute(mWorkingAttributeName)->setValue(mWorkingAttributeValue);
}
mLineState = LS::Await_Attribute_Name;
}
void XmlParser::onStartProlog()
{
mDocumentState = DS::Build_Prolog;
mLineState = LS::Await_Tag_Name_End;
}
void XmlParser::onFinishProlog()
{
mDocument->getProlog()->update();
mDocumentState = DS::Await_Element;
mLineState = LS::Await_Tag_Open;
}
XmlDocumentPtr XmlParser::getDocument()
{
return std::move(mDocument);
}

View file

@ -0,0 +1,102 @@
#pragma once
#include <string>
#include <stack>
#include <memory>
class XmlDocument;
using XmlDocumentPtr = std::unique_ptr<XmlDocument>;
class XmlElement;
class XmlParser
{
public:
enum class DocumentState
{
Await_Prolog,
Build_Prolog,
Await_Element,
Build_Element,
Close_Element
};
enum class LineState
{
Await_Tag_Open,
Await_Tag_Follower,
Await_Tag_Name,
Await_Tag_Name_End,
Await_Tag_Inline_Close,
Await_Attribute_Name,
Await_Attribute_Name_End,
Await_Attribute_Value,
Await_Attribute_Value_End,
Await_Text_End
};
public:
XmlParser();
void processLine(const std::string& input);
XmlDocumentPtr getDocument();
private:
void onLeftBracket();
void onRightBracket();
void onQuestionMark();
void onForwardSlash();
void onChar(char c);
void onSpace(char c);
void onAlphaNumeric(char c);
void onNonAlphaNumeric(char c);
void onEquals();
void onDoubleQuote();
void onTagOpen();
void onTagNameStart(char c);
void onTagNameEnd();
void onTagClose();
void onTextStart(char c);
void onTextEnd();
void onAttributeNameStart(char c);
void onAttributeNameEnd();
void onAttributeValueStart();
void onAttributeValueEnd();
void onStartProlog();
void onFinishProlog();
void onElementTagEnd();
private:
DocumentState mDocumentState;
LineState mLineState;
XmlDocumentPtr mDocument;
std::stack<XmlElement*> mWorkingElements;
std::string mWorkingAttributeName;
std::string mWorkingTagName;
std::string mWorkingAttributeValue;
std::string mWorkingText;
};

View file

@ -0,0 +1,24 @@
#include "XmlWriter.h"
#include "XmlDocument.h"
#include "XmlAttribute.h"
std::string XmlWriter::toString(XmlDocument* document)
{
std::string content;
if (auto prolog = document->getProlog())
{
content += "<?xml";
for (const auto& [key, attribute] : prolog->getAttributes())
{
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
}
content += "?>\n";
}
if (auto root = document->getRoot())
{
content += root->toString();
}
return content;
}

View file

@ -0,0 +1,14 @@
#pragma once
#include <string>
class XmlDocument;
class XmlElement;
class XmlWriter
{
public:
XmlWriter() = default;
std::string toString(XmlDocument* document);
};

View file

@ -0,0 +1,28 @@
#include "XmlAttribute.h"
XmlAttribute::XmlAttribute(const std::string& name)
: mName(name),
mValue()
{
}
XmlAttributePtr XmlAttribute::Create(const std::string& name)
{
return std::make_unique<XmlAttribute>(name);
}
const std::string& XmlAttribute::getName() const
{
return mName;
}
const std::string& XmlAttribute::getValue() const
{
return mValue;
}
void XmlAttribute::setValue(const std::string& value)
{
mValue = value;
}

View file

@ -0,0 +1,23 @@
#pragma once
#include <memory>
#include <string>
class XmlAttribute
{
public:
XmlAttribute(const std::string& name);
static std::unique_ptr<XmlAttribute> Create(const std::string& name);
const std::string& getName() const;
const std::string& getValue() const;
void setValue(const std::string& value);
private:
std::string mName;
std::string mValue;
};
using XmlAttributePtr = std::unique_ptr<XmlAttribute>;

View file

@ -0,0 +1,140 @@
#include "XmlElement.h"
#include "XmlAttribute.h"
XmlElement::XmlElement(const std::string& tagName)
: mTagName(tagName),
mChildren()
{
}
XmlElement::~XmlElement()
{
}
XmlElementPtr XmlElement::Create(const std::string& tagName)
{
return std::make_unique<XmlElement>(tagName);
}
void XmlElement::setTagName(const std::string& tagName)
{
mTagName = tagName;
}
void XmlElement::addChild(XmlElementPtr child)
{
mChildren.push_back(std::move(child));
}
void XmlElement::addAttribute(XmlAttributePtr attribute)
{
mAttributes[attribute->getName()] = std::move(attribute);
}
void XmlElement::addAttribute(const std::string& name, const std::string& value)
{
auto attr = std::make_unique<XmlAttribute>(name);
attr->setValue(value);
addAttribute(std::move(attr));
}
const std::string& XmlElement::getTagName() const
{
return mTagName;
}
const std::string& XmlElement::getText() const
{
return mText;
}
void XmlElement::setText(const std::string& text)
{
mText = text;
}
XmlElement* XmlElement::getFirstChildWithTagName(const std::string& tag)
{
for(auto& child : mChildren)
{
if (child->getTagName() == tag)
{
return child.get();
}
}
return nullptr;
}
bool XmlElement::hasAttribute(const std::string& attribute) const
{
return (bool)(getAttribute(attribute));
}
XmlAttribute* XmlElement::getAttribute(const std::string& attributeName) const
{
if (auto iter = mAttributes.find(attributeName); iter != mAttributes.end())
{
return iter->second.get();
}
return nullptr;
}
const std::unordered_map<std::string, XmlAttributePtr>& XmlElement::getAttributes() const
{
return mAttributes;
}
const std::vector<std::unique_ptr<XmlElement> >& XmlElement::getChildren() const
{
return mChildren;
}
std::string XmlElement::toString(unsigned depth, bool keepInline) const
{
const auto prefix = std::string(2*depth, ' ');
std::string line_ending = keepInline ? "" : "\n";
auto content = prefix + "<" + getTagName();
for (const auto& [key, attribute] : getAttributes())
{
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
}
const auto num_children = mChildren.size();
if (num_children == 0 && getText().empty())
{
content += "/>" + line_ending;
return content;
}
else
{
content += ">";
}
if (!getText().empty())
{
content += getText();
}
if (num_children>0)
{
content += line_ending;
}
for(const auto& child : mChildren)
{
content += child->toString(depth+1, keepInline);
}
if (num_children>0)
{
content += prefix;
}
content += "</" + getTagName() + ">" + line_ending;
return content;
}

View file

@ -0,0 +1,47 @@
#pragma once
#include <memory>
#include <vector>
#include <string>
#include <unordered_map>
class XmlAttribute;
using XmlAttributePtr = std::unique_ptr<XmlAttribute>;
class XmlElement
{
public:
XmlElement(const std::string& tagName);
virtual ~XmlElement();
static std::unique_ptr<XmlElement> Create(const std::string& tagName);
void addAttribute(XmlAttributePtr attribute);
void addAttribute(const std::string& name, const std::string& value);
void addChild(std::unique_ptr<XmlElement> child);
const std::string& getTagName() const;
const std::string& getText() const;
bool hasAttribute(const std::string& attribute) const;
XmlAttribute* getAttribute(const std::string& attribute) const;
const std::unordered_map<std::string, XmlAttributePtr>& getAttributes() const;
const std::vector<std::unique_ptr<XmlElement> >& getChildren() const;
XmlElement* getFirstChildWithTagName(const std::string& tag);
void setText(const std::string& text);
void setTagName(const std::string& tagName);
virtual std::string toString(unsigned depth = 0, bool keepInline = false) const;
protected:
std::string mTagName;
std::string mText;
std::unordered_map<std::string, XmlAttributePtr> mAttributes;
std::vector<std::unique_ptr<XmlElement> > mChildren;
};
using XmlElementPtr = std::unique_ptr<XmlElement>;

View file

@ -0,0 +1,55 @@
#include "XmlProlog.h"
#include "XmlAttribute.h"
XmlProlog::XmlProlog(const std::string& tagName)
: XmlElement(tagName),
mVersion(XmlProlog::Version::V1_0),
mEncoding(XmlProlog::Encoding::UTF8)
{
}
XmlPrologPtr XmlProlog::Create(const std::string& tagName)
{
return std::make_unique<XmlProlog>(tagName);
}
XmlProlog::Encoding XmlProlog::getEncoding() const
{
return mEncoding;
}
XmlProlog::Version XmlProlog::getVersion() const
{
return mVersion;
}
void XmlProlog::setEncoding(const std::string& encoding)
{
if(encoding == "UTF-8")
{
mEncoding = XmlProlog::Encoding::UTF8;
}
}
void XmlProlog::setVersion(const std::string& version)
{
if(version == "1.0")
{
mVersion = XmlProlog::Version::V1_0;
}
}
void XmlProlog::update()
{
if(const auto version = getAttribute("version"))
{
setVersion(version->getValue());
}
if(const auto encoding = getAttribute("encoding"))
{
setEncoding(encoding->getValue());
}
}

View file

@ -0,0 +1,36 @@
#pragma once
#include "XmlElement.h"
#include <memory>
#include <vector>
class XmlProlog : public XmlElement
{
public:
enum class Version{
V1_0
};
enum class Encoding{
UTF8
};
public:
XmlProlog(const std::string& tagName);
static std::unique_ptr<XmlProlog> Create(const std::string& tagName);
Encoding getEncoding() const;
Version getVersion() const;
void setEncoding(const std::string& encoding);
void setVersion(const std::string& version);
void update();
private:
Version mVersion;
Encoding mEncoding;
};
using XmlPrologPtr = std::unique_ptr<XmlProlog>;