diff options
Diffstat (limited to 'src/lib/util/xmlfile.cpp')
-rw-r--r-- | src/lib/util/xmlfile.cpp | 659 |
1 files changed, 343 insertions, 316 deletions
diff --git a/src/lib/util/xmlfile.cpp b/src/lib/util/xmlfile.cpp index 1014a7b245c..db8d87930e2 100644 --- a/src/lib/util/xmlfile.cpp +++ b/src/lib/util/xmlfile.cpp @@ -8,13 +8,14 @@ ***************************************************************************/ -#include <assert.h> - #include "xmlfile.h" +#include "osdcore.h" + #include <expat.h> #include <algorithm> +#include <cassert> #include <cctype> #include <cstdlib> #include <cstring> @@ -23,40 +24,73 @@ #include <sstream> -namespace util { namespace xml { +namespace util::xml { namespace { -/*************************************************************************** - CONSTANTS -***************************************************************************/ +//************************************************************************** +// CONSTANTS +//************************************************************************** constexpr unsigned TEMP_BUFFER_SIZE(4096U); -std::locale const f_portable_locale("C"); + + +//************************************************************************** +// UTILITY FUNCTIONS +//************************************************************************** + +void write_escaped(core_file &file, std::string const &str) +{ + // FIXME: check for errors + std::string::size_type pos = 0; + while ((str.size() > pos) && (std::string::npos != pos)) + { + std::string::size_type const found = str.find_first_of("\"&<>", pos); + if (found != std::string::npos) + { + write(file, &str[pos], found - pos); + switch (str[found]) + { + case '"': file.puts("""); pos = found + 1; break; + case '&': file.puts("&"); pos = found + 1; break; + case '<': file.puts("<"); pos = found + 1; break; + case '>': file.puts(">"); pos = found + 1; break; + default: pos = found; + } + } + else + { + write(file, &str[pos], str.size() - pos); + pos = found; + } + } +} } // anonymous namespace -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** struct parse_info { + parse_info() { memset(&parser, 0, sizeof(parser)); } + XML_Parser parser; file::ptr rootnode; - data_node * curnode; - uint32_t flags; + data_node * curnode = nullptr; + uint32_t flags = 0; }; -/*************************************************************************** - PROTOTYPES -***************************************************************************/ +//************************************************************************** +// PROTOTYPES +//************************************************************************** -/* expat interfaces */ +// expat interfaces static bool expat_setup_parser(parse_info &info, parse_options const *opts); static void expat_element_start(void *data, const XML_Char *name, const XML_Char **attributes); static void expat_data(void *data, const XML_Char *s, int len); @@ -64,17 +98,17 @@ static void expat_element_end(void *data, const XML_Char *name); -/*************************************************************************** - XML FILE OBJECTS -***************************************************************************/ +//************************************************************************** +// XML FILE OBJECTS +//************************************************************************** file::file() { } file::~file() { } -/*------------------------------------------------- - create - create a new, empty XML file --------------------------------------------------*/ +//------------------------------------------------- +// create - create a new, empty XML file +//------------------------------------------------- file::ptr file::create() { @@ -83,32 +117,31 @@ file::ptr file::create() } -/*------------------------------------------------- - read - parse an XML file into its nodes --------------------------------------------------*/ +//------------------------------------------------- +// read - parse an XML file into its nodes +//------------------------------------------------- -file::ptr file::read(util::core_file &file, parse_options const *opts) +file::ptr file::read(read_stream &file, parse_options const *opts) { + // set up the parser parse_info info; - int done; - - /* set up the parser */ if (!expat_setup_parser(info, opts)) return ptr(); - /* loop through the file and parse it */ + // loop through the file and parse it + bool done; do { char tempbuf[TEMP_BUFFER_SIZE]; - /* read as much as we can */ - int bytes = file.read(tempbuf, sizeof(tempbuf)); - done = file.eof(); + // read as much as we can + auto const [err, bytes] = util::read(file, tempbuf, sizeof(tempbuf)); // FIXME: better error handling + done = !bytes; - /* parse the data */ + // parse the data if (XML_Parse(info.parser, tempbuf, bytes, done) == XML_STATUS_ERROR) { - if (opts != nullptr && opts->error != nullptr) + if (opts && opts->error) { opts->error->error_message = XML_ErrorString(XML_GetErrorCode(info.parser)); opts->error->error_line = XML_GetCurrentLineNumber(info.parser); @@ -122,29 +155,29 @@ file::ptr file::read(util::core_file &file, parse_options const *opts) } while (!done); - /* free the parser */ + // free the parser XML_ParserFree(info.parser); - /* return the root node */ + // return the root node return std::move(info.rootnode); } -/*------------------------------------------------- - string_read - parse an XML string into its - nodes --------------------------------------------------*/ +//------------------------------------------------- +// string_read - parse an XML string into its +// nodes +//------------------------------------------------- file::ptr file::string_read(const char *string, parse_options const *opts) { parse_info info; int length = (int)strlen(string); - /* set up the parser */ + // set up the parser if (!expat_setup_parser(info, opts)) return ptr(); - /* parse the data */ + // parse the data if (XML_Parse(info.parser, string, length, 1) == XML_STATUS_ERROR) { if (opts != nullptr && opts->error != nullptr) @@ -159,36 +192,36 @@ file::ptr file::string_read(const char *string, parse_options const *opts) return ptr(); } - /* free the parser */ + // free the parser XML_ParserFree(info.parser); - /* return the root node */ + // return the root node return std::move(info.rootnode); } -/*------------------------------------------------- - file_write - write an XML tree to a file --------------------------------------------------*/ +//------------------------------------------------- +// file_write - write an XML tree to a file +//------------------------------------------------- void file::write(util::core_file &file) const { - /* ensure this is a root node */ + // ensure this is a root node assert(!get_name()); - /* output a simple header */ + // output a simple header file.printf("<?xml version=\"1.0\"?>\n"); file.printf("<!-- This file is autogenerated; comments and unknown tags will be stripped -->\n"); - /* loop over children of the root and output */ + // loop over children of the root and output write_recursive(0, file); } -/*************************************************************************** - XML NODE MANAGEMENT -***************************************************************************/ +//************************************************************************** +// XML NODE MANAGEMENT +//************************************************************************** data_node::data_node() : line(0) @@ -214,10 +247,10 @@ data_node::data_node(data_node *parent, const char *name, const char *value) } -/*------------------------------------------------- - free_node_recursive - recursively free - the data allocated to an XML node --------------------------------------------------*/ +//------------------------------------------------- +// free_node_recursive - recursively free +// the data allocated to an XML node +//------------------------------------------------- data_node::~data_node() { @@ -229,7 +262,7 @@ void data_node::free_children() { for (data_node *nchild = nullptr; m_first_child; m_first_child = nchild) { - /* note the next node and free this node */ + // note the next node and free this node nchild = m_first_child->get_next_sibling(); delete m_first_child; } @@ -250,13 +283,13 @@ void data_node::append_value(char const *value, int length) void data_node::trim_whitespace() { - /* first strip leading spaces */ + // first strip leading spaces std::string::iterator start = m_value.begin(); while ((m_value.end() != start) && std::isspace(uint8_t(*start))) ++start; m_value.replace(m_value.begin(), start, 0U, '\0'); - /* then strip trailing spaces */ + // then strip trailing spaces std::string::iterator end = m_value.end(); while ((m_value.begin() != end) && std::isspace(uint8_t(*std::prev(end)))) --end; @@ -264,27 +297,37 @@ void data_node::trim_whitespace() } -/*------------------------------------------------- - data_node::count_children - count the - number of child nodes --------------------------------------------------*/ +//------------------------------------------------- +// data_node::count_children - count the +// number of child nodes +//------------------------------------------------- -int data_node::count_children() const +std::size_t data_node::count_children() const { - int count = 0; - - /* loop over children and count */ + // loop over children and count + std::size_t count = 0; for (data_node const *node = get_first_child(); node; node = node->get_next_sibling()) count++; return count; } -/*------------------------------------------------- - data_node::get_child - find the first - child of the specified node with the specified - tag --------------------------------------------------*/ +//------------------------------------------------- +// data_node::count_children - count the +// number of child nodes +//------------------------------------------------- + +std::size_t data_node::count_attributes() const +{ + return m_attributes.size(); +} + + +//------------------------------------------------- +// data_node::get_child - find the first +// child of the specified node with the specified +// tag +//------------------------------------------------- data_node *data_node::get_child(const char *name) { @@ -297,11 +340,11 @@ data_node const *data_node::get_child(const char *name) const } -/*------------------------------------------------- - find_first_matching_child - find the first - child of the specified node with the - specified tag or attribute/value pair --------------------------------------------------*/ +//------------------------------------------------- +// find_first_matching_child - find the first +// child of the specified node with the +// specified tag or attribute/value pair +//------------------------------------------------- data_node *data_node::find_first_matching_child(const char *name, const char *attribute, const char *matchval) { @@ -314,11 +357,11 @@ data_node const *data_node::find_first_matching_child(const char *name, const ch } -/*------------------------------------------------- - data_node::get_next_sibling - find the - next sibling of the specified node with the - specified tag --------------------------------------------------*/ +//------------------------------------------------- +// data_node::get_next_sibling - find the +// next sibling of the specified node with the +// specified tag +//------------------------------------------------- data_node *data_node::get_next_sibling(const char *name) { @@ -331,11 +374,11 @@ data_node const *data_node::get_next_sibling(const char *name) const } -/*------------------------------------------------- - find_next_matching_sibling - find the next - sibling of the specified node with the - specified tag or attribute/value pair --------------------------------------------------*/ +//------------------------------------------------- +// find_next_matching_sibling - find the next +// sibling of the specified node with the +// specified tag or attribute/value pair +//------------------------------------------------- data_node *data_node::find_next_matching_sibling(const char *name, const char *attribute, const char *matchval) { @@ -348,17 +391,17 @@ data_node const *data_node::find_next_matching_sibling(const char *name, const c } -/*------------------------------------------------- - add_child - add a new child node to the - given node --------------------------------------------------*/ +//------------------------------------------------- +// add_child - add a new child node to the +// given node +//------------------------------------------------- data_node *data_node::add_child(const char *name, const char *value) { if (!name || !*name) return nullptr; - /* new element: create a new node */ + // new element: create a new node data_node *node; try { node = new data_node(this, name, value); } catch (...) { return nullptr; } @@ -369,7 +412,7 @@ data_node *data_node::add_child(const char *name, const char *value) return nullptr; } - /* add us to the end of the list of siblings */ + // add us to the end of the list of siblings data_node **pnode; for (pnode = &m_first_child; *pnode; pnode = &(*pnode)->m_next) { } *pnode = node; @@ -378,19 +421,19 @@ data_node *data_node::add_child(const char *name, const char *value) } -/*------------------------------------------------- - get_or_add_child - find a child node of - the specified type; if not found, add one --------------------------------------------------*/ +//------------------------------------------------- +// get_or_add_child - find a child node of +// the specified type; if not found, add one +//------------------------------------------------- data_node *data_node::get_or_add_child(const char *name, const char *value) { - /* find the child first */ + // find the child first data_node *const child = m_first_child->get_sibling(name); if (child) return child; - /* if not found, do a standard add child */ + // if not found, do a standard add child return add_child(name, value); } @@ -422,8 +465,14 @@ data_node *data_node::copy_into(data_node &parent) const } else { - dst = dst->get_parent(); - src = src->get_parent()->get_next_sibling(); + do + { + dst = dst->get_parent(); + src = src->get_parent(); + next = src->get_next_sibling(); + } + while (!next && (&parent != dst)); + src = next; } } } @@ -432,17 +481,17 @@ data_node *data_node::copy_into(data_node &parent) const } -/*------------------------------------------------- - delete_node - delete a node and its - children --------------------------------------------------*/ +//------------------------------------------------- +// delete_node - delete a node and its +// children +//------------------------------------------------- void data_node::delete_node() { - /* don't allow deletion of document root */ + // don't allow deletion of document root if (m_parent) { - /* first unhook us from the list of children of our parent */ + // first unhook us from the list of children of our parent for (data_node **pnode = &m_parent->m_first_child; *pnode; pnode = &(*pnode)->m_next) { if (*pnode == this) @@ -452,25 +501,25 @@ void data_node::delete_node() } } - /* now free ourselves and our children */ + // now free ourselves and our children delete this; } else { - /* remove all children of document root */ + // remove all children of document root free_children(); } } -/*------------------------------------------------- - get_next_sibling - find the next sibling of - the specified node with the specified tag --------------------------------------------------*/ +//------------------------------------------------- +// get_next_sibling - find the next sibling of +// the specified node with the specified tag +//------------------------------------------------- data_node *data_node::get_sibling(const char *name) { - /* loop over siblings and find a matching name */ + // loop over siblings and find a matching name for (data_node *node = this; node; node = node->get_next_sibling()) if (strcmp(node->get_name(), name) == 0) return node; @@ -479,7 +528,7 @@ data_node *data_node::get_sibling(const char *name) data_node const *data_node::get_sibling(const char *name) const { - /* loop over siblings and find a matching name */ + // loop over siblings and find a matching name for (data_node const *node = this; node; node = node->get_next_sibling()) if (strcmp(node->get_name(), name) == 0) return node; @@ -487,21 +536,21 @@ data_node const *data_node::get_sibling(const char *name) const } -/*------------------------------------------------- - find_matching_sibling - find the next - sibling of the specified node with the - specified tag or attribute/value pair --------------------------------------------------*/ +//------------------------------------------------- +// find_matching_sibling - find the next +// sibling of the specified node with the +// specified tag or attribute/value pair +//------------------------------------------------- data_node *data_node::find_matching_sibling(const char *name, const char *attribute, const char *matchval) { - /* loop over siblings and find a matching attribute */ + // loop over siblings and find a matching attribute for (data_node *node = this; node; node = node->get_next_sibling()) { - /* can pass nullptr as a wildcard for the node name */ + // can pass nullptr as a wildcard for the node name if (!name || !strcmp(name, node->get_name())) { - /* find a matching attribute */ + // find a matching attribute attribute_node const *const attr = node->get_attribute(attribute); if (attr && !strcmp(attr->value.c_str(), matchval)) return node; @@ -512,13 +561,13 @@ data_node *data_node::find_matching_sibling(const char *name, const char *attrib data_node const *data_node::find_matching_sibling(const char *name, const char *attribute, const char *matchval) const { - /* loop over siblings and find a matching attribute */ + // loop over siblings and find a matching attribute for (data_node const *node = this; node; node = node->get_next_sibling()) { - /* can pass nullptr as a wildcard for the node name */ + // can pass nullptr as a wildcard for the node name if (!name || !strcmp(name, node->get_name())) { - /* find a matching attribute */ + // find a matching attribute attribute_node const *const attr = node->get_attribute(attribute); if (attr && !strcmp(attr->value.c_str(), matchval)) return node; @@ -529,9 +578,9 @@ data_node const *data_node::find_matching_sibling(const char *name, const char * -/*************************************************************************** - XML ATTRIBUTE MANAGEMENT -***************************************************************************/ +//************************************************************************** +// XML ATTRIBUTE MANAGEMENT +//************************************************************************** bool data_node::has_attribute(const char *attribute) const { @@ -539,14 +588,14 @@ bool data_node::has_attribute(const char *attribute) const } -/*------------------------------------------------- - get_attribute - get the value of the - specified attribute, or nullptr if not found --------------------------------------------------*/ +//------------------------------------------------- +// get_attribute - get the value of the +// specified attribute, or nullptr if not found +//------------------------------------------------- data_node::attribute_node *data_node::get_attribute(const char *attribute) { - /* loop over attributes and find a match */ + // loop over attributes and find a match for (attribute_node &anode : m_attributes) if (strcmp(anode.name.c_str(), attribute) == 0) return &anode; @@ -555,7 +604,7 @@ data_node::attribute_node *data_node::get_attribute(const char *attribute) data_node::attribute_node const *data_node::get_attribute(const char *attribute) const { - /* loop over attributes and find a match */ + // loop over attributes and find a match for (attribute_node const &anode : m_attributes) if (strcmp(anode.name.c_str(), attribute) == 0) return &anode; @@ -563,11 +612,24 @@ data_node::attribute_node const *data_node::get_attribute(const char *attribute) } -/*------------------------------------------------- - get_attribute_string - get the string - value of the specified attribute; if not - found, return = the provided default --------------------------------------------------*/ +//------------------------------------------------- +// get_attribute_string_ptr - get a pointer to +// the string value of the specified attribute; +// if not found, return = nullptr +//------------------------------------------------- + +std::string const *data_node::get_attribute_string_ptr(const char *attribute) const +{ + attribute_node const *attr = get_attribute(attribute); + return attr ? &attr->value : nullptr; +} + + +//------------------------------------------------- +// get_attribute_string - get the string +// value of the specified attribute; if not +// found, return = the provided default +//------------------------------------------------- const char *data_node::get_attribute_string(const char *attribute, const char *defvalue) const { @@ -576,34 +638,35 @@ const char *data_node::get_attribute_string(const char *attribute, const char *d } -/*------------------------------------------------- - get_attribute_int - get the integer - value of the specified attribute; if not - found, return = the provided default --------------------------------------------------*/ +//------------------------------------------------- +// get_attribute_int - get the integer +// value of the specified attribute; if not +// found, return = the provided default +//------------------------------------------------- -int data_node::get_attribute_int(const char *attribute, int defvalue) const +long long data_node::get_attribute_int(const char *attribute, long long defvalue) const { - char const *const string = get_attribute_string(attribute, nullptr); - if (!string) + attribute_node const *attr = get_attribute(attribute); + if (!attr) return defvalue; + std::string const &string = attr->value; std::istringstream stream; - stream.imbue(f_portable_locale); - int result; + stream.imbue(std::locale::classic()); + long long result; if (string[0] == '$') { stream.str(&string[1]); - unsigned uvalue; + unsigned long long uvalue; stream >> std::hex >> uvalue; - result = int(uvalue); + result = static_cast<long long>(uvalue); } else if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) { stream.str(&string[2]); - unsigned uvalue; + unsigned long long uvalue; stream >> std::hex >> uvalue; - result = int(uvalue); + result = static_cast<long long>(uvalue); } else if (string[0] == '#') { @@ -620,179 +683,139 @@ int data_node::get_attribute_int(const char *attribute, int defvalue) const } -/*------------------------------------------------- - get_attribute_int_format - return the - format of the given integer attribute --------------------------------------------------*/ +//------------------------------------------------- +// get_attribute_int_format - return the +// format of the given integer attribute +//------------------------------------------------- data_node::int_format data_node::get_attribute_int_format(const char *attribute) const { - char const *const string = get_attribute_string(attribute, nullptr); - if (!string) + attribute_node const *attr = get_attribute(attribute); + if (!attr) return int_format::DECIMAL; - else if (string[0] == '$') + std::string const &string = attr->value; + + if (string[0] == '$') return int_format::HEX_DOLLAR; else if (string[0] == '0' && string[1] == 'x') return int_format::HEX_C; - if (string[0] == '#') + else if (string[0] == '#') return int_format::DECIMAL_HASH; else return int_format::DECIMAL; } -/*------------------------------------------------- - get_attribute_float - get the float - value of the specified attribute; if not - found, return = the provided default --------------------------------------------------*/ +//------------------------------------------------- +// get_attribute_float - get the float +// value of the specified attribute; if not +// found, return = the provided default +//------------------------------------------------- float data_node::get_attribute_float(const char *attribute, float defvalue) const { - char const *const string = get_attribute_string(attribute, nullptr); - if (!string) + attribute_node const *attr = get_attribute(attribute); + if (!attr) return defvalue; - std::istringstream stream(string); - stream.imbue(f_portable_locale); + std::istringstream stream(attr->value); + stream.imbue(std::locale::classic()); float result; return (stream >> result) ? result : defvalue; } -/*------------------------------------------------- - set_attribute - set a new attribute and - string value on the node --------------------------------------------------*/ +//------------------------------------------------- +// set_attribute - set a new attribute and +// string value on the node +//------------------------------------------------- void data_node::set_attribute(const char *name, const char *value) { attribute_node *anode; - /* first find an existing one to replace */ + // first find an existing one to replace anode = get_attribute(name); if (anode != nullptr) { - /* if we found it, free the old value and replace it */ + // if we found it, free the old value and replace it anode->value = value; } else { - /* otherwise, create a new node */ + // otherwise, create a new node add_attribute(name, value); } } -/*------------------------------------------------- - set_attribute_int - set a new attribute and - integer value on the node --------------------------------------------------*/ +//------------------------------------------------- +// set_attribute_int - set a new attribute and +// integer value on the node +//------------------------------------------------- -void data_node::set_attribute_int(const char *name, int value) +void data_node::set_attribute_int(const char *name, long long value) { - set_attribute(name, string_format(f_portable_locale, "%d", value).c_str()); + set_attribute(name, string_format(std::locale::classic(), "%d", value).c_str()); } -/*------------------------------------------------- - set_attribute_int - set a new attribute and - float value on the node --------------------------------------------------*/ +//------------------------------------------------- +// set_attribute_int - set a new attribute and +// float value on the node +//------------------------------------------------- void data_node::set_attribute_float(const char *name, float value) { - set_attribute(name, string_format(f_portable_locale, "%f", value).c_str()); + set_attribute(name, string_format(std::locale::classic(), "%f", value).c_str()); } -/*************************************************************************** - MISCELLANEOUS INTERFACES -***************************************************************************/ +//************************************************************************** +// MISCELLANEOUS INTERFACES +//************************************************************************** -/*------------------------------------------------- - normalize_string - normalize a string - to ensure it doesn't contain embedded tags --------------------------------------------------*/ +//------------------------------------------------- +// normalize_string - normalize a string +// to ensure it doesn't contain embedded tags +//------------------------------------------------- -const char *normalize_string(const char *string) +std::string normalize_string(std::string_view string) { - static char buffer[1024]; - char *d = &buffer[0]; + std::string result; + result.reserve(string.length()); - if (string != nullptr) + for (char ch : string) { - while (*string) + switch (ch) { - switch (*string) - { - case '\"' : d += sprintf(d, """); break; - case '&' : d += sprintf(d, "&"); break; - case '<' : d += sprintf(d, "<"); break; - case '>' : d += sprintf(d, ">"); break; - default: - *d++ = *string; - } - ++string; + case '\"': result.append("""); break; + case '&': result.append("&"); break; + case '<': result.append("<"); break; + case '>': result.append(">"); break; + default: result.append(1, ch); break; } } - *d++ = 0; - return buffer; -} - - - -/*************************************************************************** - EXPAT INTERFACES -***************************************************************************/ - -/*------------------------------------------------- - expat_malloc/expat_realloc/expat_free - - wrappers for memory allocation functions so - that they pass through out memory tracking - systems --------------------------------------------------*/ -static void *expat_malloc(size_t size) -{ - uint32_t *result = (uint32_t *)malloc(size + 4 * sizeof(uint32_t)); - *result = size; - return &result[4]; + return result; } -static void expat_free(void *ptr) -{ - if (ptr != nullptr) - free(&((uint32_t *)ptr)[-4]); -} -static void *expat_realloc(void *ptr, size_t size) -{ - void *newptr = expat_malloc(size); - if (newptr == nullptr) - return nullptr; - if (ptr != nullptr) - { - uint32_t oldsize = ((uint32_t *)ptr)[-4]; - memcpy(newptr, ptr, oldsize); - expat_free(ptr); - } - return newptr; -} +//************************************************************************** +// EXPAT INTERFACES +//************************************************************************** -/*------------------------------------------------- - expat_setup_parser - set up expat for parsing --------------------------------------------------*/ +//------------------------------------------------- +// expat_setup_parser - set up expat for parsing +//------------------------------------------------- static bool expat_setup_parser(parse_info &info, parse_options const *opts) { - XML_Memory_Handling_Suite memcallbacks; - - /* setup info structure */ - memset(&info, 0, sizeof(info)); + // setup info structure + info = parse_info(); if (opts != nullptr) { info.flags = opts->flags; @@ -804,105 +827,102 @@ static bool expat_setup_parser(parse_info &info, parse_options const *opts) } } - /* create a root node */ + // create a root node info.rootnode = file::create(); if (!info.rootnode) return false; info.curnode = info.rootnode.get(); - /* create the XML parser */ - memcallbacks.malloc_fcn = expat_malloc; - memcallbacks.realloc_fcn = expat_realloc; - memcallbacks.free_fcn = expat_free; - info.parser = XML_ParserCreate_MM(nullptr, &memcallbacks, nullptr); - if (info.parser == nullptr) + // create the XML parser + info.parser = XML_ParserCreate(nullptr); + if (!info.parser) { info.rootnode.reset(); return false; } - /* configure the parser */ + // configure the parser XML_SetElementHandler(info.parser, expat_element_start, expat_element_end); XML_SetCharacterDataHandler(info.parser, expat_data); XML_SetUserData(info.parser, &info); - /* optional parser initialization step */ + // optional parser initialization step if (opts != nullptr && opts->init_parser != nullptr) (*opts->init_parser)(info.parser); return true; } -/*------------------------------------------------- - expat_element_start - expat callback for a new - element --------------------------------------------------*/ +//------------------------------------------------ +// expat_element_start - expat callback for a new +// element +//------------------------------------------------ static void expat_element_start(void *data, const XML_Char *name, const XML_Char **attributes) { - parse_info *info = (parse_info *) data; + auto *info = (parse_info *) data; data_node **curnode = &info->curnode; data_node *newnode; int attr; - /* add a new child node to the current node */ + // add a new child node to the current node newnode = (*curnode)->add_child(name, nullptr); if (newnode == nullptr) return; - /* remember the line number */ + // remember the line number newnode->line = XML_GetCurrentLineNumber(info->parser); - /* add all the attributes as well */ + // add all the attributes as well for (attr = 0; attributes[attr]; attr += 2) newnode->add_attribute(attributes[attr+0], attributes[attr+1]); - /* set us up as the current node */ + // set us up as the current node *curnode = newnode; } -/*------------------------------------------------- - expat_data - expat callback for an additional - element data --------------------------------------------------*/ +//------------------------------------------------- +// expat_data - expat callback for an additional +// element data +//------------------------------------------------- static void expat_data(void *data, const XML_Char *s, int len) { - parse_info *info = (parse_info *) data; + auto *info = (parse_info *) data; data_node **curnode = &info->curnode; (*curnode)->append_value(s, len); } -/*------------------------------------------------- - expat_element_end - expat callback for the end - of an element --------------------------------------------------*/ +//------------------------------------------------- +// expat_element_end - expat callback for the end +// of an element +//------------------------------------------------- static void expat_element_end(void *data, const XML_Char *name) { - parse_info *info = (parse_info *) data; + auto *info = (parse_info *) data; data_node **curnode = &info->curnode; - /* strip leading/trailing spaces from the value data */ + // strip leading/trailing spaces from the value data if (!(info->flags & PARSE_FLAG_WHITESPACE_SIGNIFICANT)) (*curnode)->trim_whitespace(); - /* back us up a node */ + // back us up a node *curnode = (*curnode)->get_parent(); } -/*************************************************************************** - NODE/ATTRIBUTE ADDITIONS -***************************************************************************/ +//************************************************************************** +// NODE/ATTRIBUTE ADDITIONS +//************************************************************************** -/*------------------------------------------------- - add_attribute - add a new attribute to the - given node --------------------------------------------------*/ +//------------------------------------------------- +// add_attribute - add a new attribute to the +// given node +//------------------------------------------------- void data_node::add_attribute(const char *name, const char *value) { @@ -919,58 +939,65 @@ void data_node::add_attribute(const char *name, const char *value) -/*************************************************************************** - RECURSIVE TREE OPERATIONS -***************************************************************************/ +//************************************************************************** +// RECURSIVE TREE OPERATIONS +//************************************************************************** -/*------------------------------------------------- - write_node_recursive - recursively write - an XML node and its children to a file --------------------------------------------------*/ +//------------------------------------------------- +// write_node_recursive - recursively write +// an XML node and its children to a file +//------------------------------------------------- void data_node::write_recursive(int indent, util::core_file &file) const { if (!get_name()) { - /* root node doesn't generate tag */ + // root node doesn't generate tag for (data_node const *child = this->get_first_child(); child; child = child->get_next_sibling()) child->write_recursive(indent, file); } else { - /* output this tag */ + // output this tag file.printf("%*s<%s", indent, "", get_name()); - /* output any attributes */ + // output any attributes, escaping as necessary for (attribute_node const &anode : m_attributes) - file.printf(" %s=\"%s\"", anode.name, anode.value); + { + file.printf(" %s=\"", anode.name); + write_escaped(file, anode.value); + file.puts("\""); + } if (!get_first_child() && !get_value()) { - /* if there are no children and no value, end the tag here */ + // if there are no children and no value, end the tag here file.printf(" />\n"); } else { - /* otherwise, close this tag and output more stuff */ + // otherwise, close this tag and output more stuff file.printf(">\n"); - /* if there is a value, output that here */ - if (get_value()) - file.printf("%*s%s\n", indent + 4, "", get_value()); + // if there is a value, output that here + if (!m_value.empty()) + { + file.printf("%*s", indent + 4, ""); + write_escaped(file, m_value); + file.puts("\n"); + } - /* loop over children and output them as well */ + // loop over children and output them as well if (get_first_child()) { for (data_node const *child = this->get_first_child(); child; child = child->get_next_sibling()) child->write_recursive(indent + 4, file); } - /* write a closing tag */ + // write a closing tag file.printf("%*s</%s>\n", indent, "", get_name()); } } } - -} } // namespace util::xml +} // namespace util::xml |