OXYGENHUB
◆ main openmsx / src / config / XMLEscape.hh
2.1 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
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).
21
template<typename Output>
22
inline 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.
66
inline 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