openMSX
XMLEscape.hh
Go to the documentation of this file.
1#ifndef XMLESCAPE_HH
2#define XMLESCAPE_HH
3
4#include <array>
5#include <string>
6#include <string_view>
7
8// The following routines do the following substitutions:
9// & -> &amp; must always be done
10// < -> &lt; must always be done
11// > -> &gt; always allowed, but must be done when it appears as ]]>
12// ' -> &apos; always allowed, but must be done inside quoted attribute
13// " -> &quot; always allowed, but must be done inside quoted attribute
14// all chars less than 32 -> &#xnn;
15// So to simplify things we always do these 5+32 substitutions.
16
17// This is a low-level version. It takes an input string and an output-functor.
18// That functor is called (possibly) multiple times, each with a (small) chunk
19// for the final output (chunk are either parts of the input or xml escape
20// sequences).
21template<typename Output>
22inline void XMLEscape(std::string_view s, Output output)
23{
24 auto chunk = s.begin();
25 auto last = s.end();
26 auto it = chunk;
27 while (it != last) {
28 char c = *it;
29 if (auto uc = static_cast<unsigned char>(c); uc < 32) {
30 output(std::string_view(chunk, it));
31 std::array<char, 6> buf = {'&', '#', 'x', '0', '0', ';'};
32 auto hex = [](unsigned x) { return (x < 10) ? char(x + '0') : char(x - 10 + 'a'); };
33 buf[3] = hex(uc / 16);
34 buf[4] = hex(uc % 16);
35 output(std::string_view(buf.data(), sizeof(buf)));
36 chunk = ++it;
37 } else if (c == '<') {
38 output(std::string_view(chunk, it));
39 output("&lt;");
40 chunk = ++it;
41 } else if (c == '>') {
42 output(std::string_view(chunk, it));
43 output("&gt;");
44 chunk = ++it;
45 } else if (c == '&') {
46 output(std::string_view(chunk, it));
47 output("&amp;");
48 chunk = ++it;
49 } else if (c == '"') {
50 output(std::string_view(chunk, it));
51 output("&quot;");
52 chunk = ++it;
53 } else if (c == '\'') {
54 output(std::string_view(chunk, it));
55 output("&apos;");
56 chunk = ++it;
57 } else {
58 // no output yet
59 ++it;
60 }
61 }
62 output(std::string_view(chunk, last));
63}
64
65// Like above, but produces the output as a (single) std::string.
66inline std::string XMLEscape(std::string_view s)
67{
68 std::string result;
69 XMLEscape(s, [&](std::string_view chunk) { result += chunk; });
70 return result;
71}
72
73#endif
void XMLEscape(std::string_view s, Output output)
Definition XMLEscape.hh:22