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 normal = [&](auto f, auto l) {
25 // c++20 std::string_view(f, l);
26 return std::string_view(&*f, l - f);
27 };
28
29 auto chunk = s.begin();
30 auto last = s.end();
31 auto it = chunk;
32 while (it != last) {
33 char c = *it;
34 if (auto uc = static_cast<unsigned char>(c); uc < 32) {
35 output(normal(chunk, it));
36 std::array<char, 6> buf = {'&', '#', 'x', '0', '0', ';'};
37 auto hex = [](unsigned x) { return (x < 10) ? char(x + '0') : char(x - 10 + 'a'); };
38 buf[3] = hex(uc / 16);
39 buf[4] = hex(uc % 16);
40 output(std::string_view(buf.data(), sizeof(buf)));
41 chunk = ++it;
42 } else if (c == '<') {
43 output(normal(chunk, it));
44 output("&lt;");
45 chunk = ++it;
46 } else if (c == '>') {
47 output(normal(chunk, it));
48 output("&gt;");
49 chunk = ++it;
50 } else if (c == '&') {
51 output(normal(chunk, it));
52 output("&amp;");
53 chunk = ++it;
54 } else if (c == '"') {
55 output(normal(chunk, it));
56 output("&quot;");
57 chunk = ++it;
58 } else if (c == '\'') {
59 output(normal(chunk, it));
60 output("&apos;");
61 chunk = ++it;
62 } else {
63 // no output yet
64 ++it;
65 }
66 }
67 output(normal(chunk, last));
68}
69
70// Like above, but produces the output as a (single) std::string.
71inline std::string XMLEscape(std::string_view s)
72{
73 std::string result;
74 XMLEscape(s, [&](std::string_view chunk) { result += chunk; });
75 return result;
76}
77
78#endif
void XMLEscape(std::string_view s, Output output)
Definition XMLEscape.hh:22