feat(xml): add XML functions

This commit is contained in:
fallenoak 2022-12-30 16:57:19 -06:00 committed by GitHub
parent 125ffec928
commit 4e43886e37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
142 changed files with 68501 additions and 0 deletions

View file

@ -5,6 +5,7 @@ file(GLOB COMMON_SOURCES
"ref/*.cpp"
"string/*.cpp"
"thread/*.cpp"
"xml/*.cpp"
)
add_library(common STATIC
@ -18,5 +19,6 @@ target_include_directories(common
target_link_libraries(common
PUBLIC
expat-2.0
storm
)

8
common/XML.hpp Normal file
View file

@ -0,0 +1,8 @@
#ifndef COMMON_XML_HPP
#define COMMON_XML_HPP
#include "xml/XMLAttribute.hpp"
#include "xml/XMLNode.hpp"
#include "xml/XMLTree.hpp"
#endif

8
common/xml/Expat.hpp Normal file
View file

@ -0,0 +1,8 @@
#ifndef COMMON_XML_EXPAT_HPP
#define COMMON_XML_EXPAT_HPP
extern "C" {
#include "expat.h"
}
#endif

View file

@ -0,0 +1,13 @@
#ifndef COMMON_XML_XML_ATTRIBUTE_HPP
#define COMMON_XML_XML_ATTRIBUTE_HPP
#include "common/String.hpp"
class XMLAttribute {
public:
// Member variables
RCString m_name;
RCString m_value;
};
#endif

83
common/xml/XMLNode.cpp Normal file
View file

@ -0,0 +1,83 @@
#include "common/xml/XMLNode.hpp"
#include <storm/String.hpp>
XMLNode::XMLNode() {
// TODO
}
XMLNode::~XMLNode() {
// TODO
}
const char* XMLNode::GetAttributeByName(const char* name) {
for (int32_t i = 0; i < this->m_attributes.Count(); i++) {
auto& attribute = this->m_attributes[i];
if (!SStrCmpI(attribute.m_name.GetString(), name, STORM_MAX_STR)) {
return attribute.m_value.GetString();
}
}
return nullptr;
}
const char* XMLNode::GetBody() const {
return this->m_body;
}
XMLNode* XMLNode::GetChildByName(const char* name) {
auto child = this->m_child;
if (!child) {
return nullptr;
}
while (SStrCmpI(child->m_name.GetString(), name, STORM_MAX_STR)) {
child = child->m_next;
if (!child) {
return nullptr;
}
}
return child;
}
const char* XMLNode::GetName() {
return this->m_name.GetString();
}
void XMLNode::Init(XMLNode* parent, const char* name) {
RCString(this->m_name);
TSGrowableArray<XMLAttribute>(this->m_attributes);
this->m_parent = parent;
this->m_child = nullptr;
this->m_name.Copy(name);
this->m_body = nullptr;
this->m_bodyLen = 0;
if (this->m_parent && this->m_parent->m_body) {
this->m_next = nullptr;
this->m_userData = nullptr;
this->m_offset = this->m_parent->m_bodyLen;
} else {
this->m_offset = 0;
this->m_next = nullptr;
this->m_userData = nullptr;
}
}
void XMLNode::SetAttribute(const char* name, const char* value) {
auto attributeCount = this->m_attributes.Count();
for (int32_t i = 0; i < attributeCount; i++) {
if (!SStrCmpI(name, this->m_attributes[i].m_name.GetString(), STORM_MAX_STR)) {
this->m_attributes[i].m_value.Copy(value);
return;
}
}
this->m_attributes.SetCount(attributeCount + 1);
this->m_attributes[attributeCount].m_name.Copy(name);
this->m_attributes[attributeCount].m_value.Copy(value);
}

33
common/xml/XMLNode.hpp Normal file
View file

@ -0,0 +1,33 @@
#ifndef COMMON_XML_XML_NODE_HPP
#define COMMON_XML_XML_NODE_HPP
#include "common/String.hpp"
#include "common/xml/XMLAttribute.hpp"
#include <cstdint>
#include <storm/Array.hpp>
class XMLNode {
public:
// Member variables
void* m_userData;
XMLNode* m_parent;
XMLNode* m_child;
RCString m_name;
char* m_body;
uint32_t m_bodyLen;
TSGrowableArray<XMLAttribute> m_attributes;
uint32_t m_offset;
XMLNode* m_next;
// Member functions
XMLNode();
~XMLNode();
const char* GetAttributeByName(const char* name);
const char* GetBody() const;
XMLNode* GetChildByName(const char* name);
const char* GetName();
void Init(XMLNode* parent, const char* name);
void SetAttribute(const char* name, const char* value);
};
#endif

140
common/xml/XMLTree.cpp Normal file
View file

@ -0,0 +1,140 @@
#include "common/xml/XMLTree.hpp"
#include "common/xml/Expat.hpp"
#include "common/xml/XMLNode.hpp"
XML_Parser XMLTreeParser;
void* XMLNodeFreeList = nullptr;
void begin_element(void* userData, const XML_Char* name, const XML_Char** atts) {
auto tree = static_cast<XMLTree*>(userData);
XMLNode* node;
if (XMLNodeFreeList) {
// TODO allocate node off of free list
} else {
// TODO allocate node off of node heap
// XMLNode* node = XMLNode::s_XMLNodeHeap->GetData(0, __FILE__, __LINE__);
node = new XMLNode;
node->Init(tree->leaf, name);
}
auto leaf = tree->leaf;
if (leaf) {
XMLNode* child = leaf->m_child;
if (child) {
for (; child->m_next; child = child->m_next)
;
child->m_next = node;
} else {
leaf->m_child = node;
}
} else {
tree->root = node;
}
tree->leaf = node;
const char** v9 = atts;
int32_t attCount = 0;
// Count attributes
if (*atts) {
do {
v9 += 2;
attCount++;
} while (*v9);
}
node->m_attributes.SetCount(attCount);
for (int32_t i = 0; i < attCount; i++) {
node->m_attributes[i].m_name.Copy(atts[i * 2]);
node->m_attributes[i].m_value.Copy(atts[i * 2 + 1]);
}
}
void end_element(void* userData, const XML_Char* name) {
XMLTree* tree = static_cast<XMLTree*>(userData);
tree->leaf = tree->leaf->m_parent;
}
void handle_body(void* userData, const XML_Char* s, int32_t len) {
if (len == 0) {
return;
}
XMLTree* tree = static_cast<XMLTree*>(userData);
XMLNode* node = tree->leaf;
if (!node->m_body) {
// Only set initial body if string contains non-whitespace
char v3;
int32_t v6 = 0;
while (1) {
v3 = s[v6];
if (v3 != ' ' && v3 != '\t' && v3 != '\r' && v3 != '\n') {
break;
}
v6++;
if (v6 >= len) {
return;
}
}
}
// Allocate / expand if necessary
char* v7 = static_cast<char*>(SMemReAlloc(node->m_body, node->m_bodyLen + len + 1, __FILE__, __LINE__, 0x0));
node->m_body = v7;
// Append character data to end of existing body
char* v8 = &v7[node->m_bodyLen];
memcpy(v8, s, len);
node->m_bodyLen += len;
// Null terminate the body
node->m_body[node->m_bodyLen] = '\0';
}
void XMLTree_Free(XMLTree* tree) {
// TODO
}
XMLNode* XMLTree_GetRoot(XMLTree* tree) {
return tree->root;
}
XMLTree* XMLTree_Load(const char* data, uint32_t length) {
XMLTree* tree = static_cast<XMLTree*>(SMemAlloc(sizeof(XMLTree), __FILE__, __LINE__, 0x8));
if (XMLTreeParser) {
XML_ParserReset(XMLTreeParser, nullptr);
} else {
XMLTreeParser = XML_ParserCreate(nullptr);
}
XML_SetElementHandler(XMLTreeParser, begin_element, end_element);
XML_SetCharacterDataHandler(XMLTreeParser, handle_body);
XML_SetUserData(XMLTreeParser, tree);
if (XML_Parse(XMLTreeParser, data, length, 1)) {
return tree;
} else {
if (tree->root) {
// TODO
// root->Recycle();
}
SMemFree(tree, __FILE__, __LINE__, 0x0);
}
return nullptr;
}

21
common/xml/XMLTree.hpp Normal file
View file

@ -0,0 +1,21 @@
#ifndef COMMON_XML_XML_TREE_HPP
#define COMMON_XML_XML_TREE_HPP
#include <cstdint>
class XMLNode;
struct XMLTree {
XMLNode* root;
XMLNode* leaf;
};
void XMLTree_Cleanup();
void XMLTree_Free(XMLTree* tree);
XMLNode* XMLTree_GetRoot(XMLTree* tree);
XMLTree* XMLTree_Load(const char* data, uint32_t length);
#endif