OXYGENHUB
◆ main openmsx / src / events / AdhocCliCommParser.cc
4.1 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "AdhocCliCommParser.hh"
2
3
#include "utf8_unchecked.hh"
4
5
AdhocCliCommParser::AdhocCliCommParser(std::function<void(const std::string&)> callback_)
6
	: callback(std::move(callback_))
7
{
8
}
9
10
void AdhocCliCommParser::parse(std::span<const char> buf)
11
{
12
	for (auto c : buf) {
13
		parse(c);
14
	}
15
}
16
17
void AdhocCliCommParser::parse(char c)
18
{
19
	// Whenever there is a parse error we return to the initial state
20
	switch (state) {
21
	case O0: // looking for opening tag
22
		state = (c == '<') ? O1 : O0; break;
23
	case O1: // matched <
24
		state = (c == 'c') ? O2 : O0; break;
25
	case O2: // matched <c
26
		state = (c == 'o') ? O3 : O0; break;
27
	case O3: // matched <co
28
		state = (c == 'm') ? O4 : O0; break;
29
	case O4: // matched <com
30
		state = (c == 'm') ? O5 : O0; break;
31
	case O5: // matched <comm
32
		state = (c == 'a') ? O6 : O0; break;
33
	case O6: // matched <comma
34
		state = (c == 'n') ? O7 : O0; break;
35
	case O7: // matched <comman
36
		state = (c == 'd') ? O8 : O0; break;
37
	case O8: // matched <command
38
		if (c == '>') {
39
			state = C0;
40
			command.clear();
41
		} else {
42
			state = O0;
43
		}
44
		break;
45
	case C0: // matched <command>, now parsing xml entities and </command>
46
		if      (c == '<') state = C1;
47
		else if (c == '&') state = A1;
48
		else command += c;
49
		break;
50
	case C1: // matched <
51
		state = (c == '/') ? C2 : O0; break;
52
	case C2: // matched </
53
		state = (c == 'c') ? C3 : O0; break;
54
	case C3: // matched </c
55
		state = (c == 'o') ? C4 : O0; break;
56
	case C4: // matched </co
57
		state = (c == 'm') ? C5 : O0; break;
58
	case C5: // matched </com
59
		state = (c == 'm') ? C6 : O0; break;
60
	case C6: // matched </comm
61
		state = (c == 'a') ? C7 : O0; break;
62
	case C7: // matched </comma
63
		state = (c == 'n') ? C8 : O0; break;
64
	case C8: // matched </comman
65
		state = (c == 'd') ? C9 : O0; break;
66
	case C9: // matched </command
67
		if (c == '>') callback(command);
68
		state = O0;
69
		break;
70
	case A1: // matched &
71
		if      (c == 'l') state = L2;
72
		else if (c == 'a') state = A2;
73
		else if (c == 'g') state = G2;
74
		else if (c == 'q') state = Q2;
75
		else if (c == '#') { state = H2; unicode = 0; }
76
		else               state = O0; // error
77
		break;
78
	case A2: // matched &a
79
		if      (c == 'm') state = A3;
80
		else if (c == 'p') state = P3;
81
		else               state = O0; // error
82
		break;
83
	case A3: // matched &am
84
		state = (c == 'p') ? A4 : O0; break;
85
	case A4: // matched &amp
86
		if (c == ';') {
87
			command += '&';
88
			state = C0;
89
		} else {
90
			state = O0; // error
91
		}
92
		break;
93
	case P3: // matched &ap
94
		state = (c == 'o') ? P4 : O0; break;
95
	case P4: // matched &apo
96
		state = (c == 's') ? P5 : O0; break;
97
	case P5: // matched &apos
98
		if (c == ';') {
99
			command += '\'';
100
			state = C0;
101
		} else {
102
			state = O0; // error
103
		}
104
		break;
105
	case Q2: // matched &q
106
		state = (c == 'u') ? Q3 : O0; break;
107
	case Q3: // matched &qu
108
		state = (c == 'o') ? Q4 : O0; break;
109
	case Q4: // matched &quo
110
		state = (c == 't') ? Q5 : O0; break;
111
	case Q5: // matched &quot
112
		if (c == ';') {
113
			command += '"';
114
			state = C0;
115
		} else {
116
			state = O0; // error
117
		}
118
		break;
119
	case G2: // matched &g
120
		state = (c == 't') ? G3 : O0; break;
121
	case G3: // matched &gt
122
		if (c == ';') {
123
			command += '>';
124
			state = C0;
125
		} else {
126
			state = O0; // error
127
		}
128
		break;
129
	case L2: // matched &l
130
		state = (c == 't') ? L3 : O0; break;
131
	case L3: // matched &lt
132
		if (c == ';') {
133
			command += '<';
134
			state = C0;
135
		} else {
136
			state = O0; // error
137
		}
138
		break;
139
	case H2: // matched &#
140
		// This also parses invalid input like '&#12xab;' but let's
141
		// ignore that. It also doesn't check for overflow etc.
142
		if (c == ';') {
143
			utf8::unchecked::append(unicode, back_inserter(command));
144
			state = C0;
145
		} else if (c == 'x') {
146
			state = H3;
147
		} else {
148
			unicode *= 10;
149
			if (('0' <= c) && (c <= '9')) unicode += c - '0';
150
			else state = O0;
151
		}
152
		break;
153
	case H3: // matched &#x
154
		if (c == ';') {
155
			utf8::unchecked::append(unicode, back_inserter(command));
156
			state = C0;
157
		} else {
158
			unicode *= 16;
159
			if      (('0' <= c) && (c <= '9')) unicode += c - '0';
160
			else if (('a' <= c) && (c <= 'f')) unicode += c - 'a' + 10;
161
			else if (('A' <= c) && (c <= 'F')) unicode += c - 'A' + 10;
162
			else state = O0;
163
		}
164
		break;
165
	}
166
}