diff options
author | 2020-09-06 01:41:44 +1000 | |
---|---|---|
committer | 2020-09-06 01:41:44 +1000 | |
commit | 94601c77cc5b645a7738d634fb6e668dfd98d6db (patch) | |
tree | feaddeac4cbb07e66f29cd3fd08c508a2a10339a /src/lib/util/xmlfile.cpp | |
parent | 080826aac441562e168fbd82eaa6bc27d2bd19a2 (diff) |
-util/xmlfile: Escape attribute and element content.
The previous behaviour was unintuitive - parsing an XML file and writing
it out immediately would produce invalid XML if the file contained any
characters that needed escaping. It makes far more sense to escape on
writing rather than expecting the user to escape input.
-Add preliminary support for visibility toggles to artwork system.
This allows the user to show/hide related elements in a view, with
nesting. The view can specify whether elements are shown or hidden by
default. Settings are saved per host window/screen per view. There is
no way to set the initial visibility state on the command line. Legacy
"Space Invaders cabinet model" layers are mapped onto visibility
toggles.
This is not stable yet. In particular, the XML element/attribute names
have not been finalised. The new features have not been added to
complay.py to prevent them from being used before they're finalised.
Diffstat (limited to 'src/lib/util/xmlfile.cpp')
-rw-r--r-- | src/lib/util/xmlfile.cpp | 46 |
1 files changed, 42 insertions, 4 deletions
diff --git a/src/lib/util/xmlfile.cpp b/src/lib/util/xmlfile.cpp index ad4d4e1e8f8..af5f36fae0d 100644 --- a/src/lib/util/xmlfile.cpp +++ b/src/lib/util/xmlfile.cpp @@ -33,6 +33,37 @@ namespace { 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) +{ + 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) + { + file.write(&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 + { + file.write(&str[pos], str.size() - pos); + pos = found; + } + } +} + } // anonymous namespace @@ -950,9 +981,13 @@ void data_node::write_recursive(int indent, util::core_file &file) const /* 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()) { @@ -965,8 +1000,11 @@ void data_node::write_recursive(int indent, util::core_file &file) const file.printf(">\n"); /* if there is a value, output that here */ - if (get_value()) - file.printf("%*s%s\n", indent + 4, "", get_value()); + if (!m_value.empty()) + { + file.printf("%*s\n", indent + 4, ""); + write_escaped(file, m_value); + } /* loop over children and output them as well */ if (get_first_child()) |