Mercurial > libanimone
annotate src/player.cc @ 32:93224b26a0ee default tip
player: efforts towards C-ization
author | Paper <paper@tflc.us> |
---|---|
date | Mon, 10 Feb 2025 19:17:29 -0500 |
parents | 973734ebd2be |
children |
rev | line source |
---|---|
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
1 #include "animone/player.h" |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
2 #include "animone/util.h" |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
3 |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
4 #include <map> |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
5 #include <sstream> |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
6 #include <string> |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
7 #include <vector> |
21
973734ebd2be
dep/animone: REFACTOR ALL THE THINGS
Paper <paper@paper.us.eu.org>
parents:
14
diff
changeset
|
8 |
973734ebd2be
dep/animone: REFACTOR ALL THE THINGS
Paper <paper@paper.us.eu.org>
parents:
14
diff
changeset
|
9 #include <iostream> |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
10 |
32 | 11 #include <string.h> |
12 #include <stdio.h> | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
13 |
32 | 14 // simple crc32-hash function, derived from Hacker's Delight |
15 // and expects a C-string as input. | |
16 // `n` should be the amount of the largest expected value of | |
17 // the hash. | |
18 static inline constexpr uint32_t crcn32b(unsigned char *message, size_t n) | |
19 { | |
20 uint32_t crc = 0xFFFFFFFF; | |
21 size_t i = 0, j = 0; | |
21
973734ebd2be
dep/animone: REFACTOR ALL THE THINGS
Paper <paper@paper.us.eu.org>
parents:
14
diff
changeset
|
22 |
32 | 23 for (i = 0; message[i] && i < n; i++) { |
24 crc = crc ^ message[i]; | |
25 for (j = 0; j < 8; j++) | |
26 crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1)); | |
27 } | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
28 |
32 | 29 return ~crc; |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
30 } |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
31 |
32 | 32 typedef enum StateName { |
33 STATENAME_EXPECTPLAYERNAME = 0, | |
34 STATENAME_EXPECTSECTION, | |
35 STATENAME_EXPECTWINDOWPLATFORM, | |
36 STATENAME_EXPECTEXECUTABLEPLATFORM, | |
37 STATENAME_EXPECTWINDOW, | |
38 STATENAME_EXPECTEXECUTABLE, | |
39 STATENAME_EXPECTSTRATEGY, | |
40 STATENAME_EXPECTTYPE, | |
41 STATENAME_EXPECTWINDOWTITLE, | |
42 } StateName; | |
43 | |
44 typedef struct State { | |
45 StateName state; | |
46 | |
47 animone::WindowPlatform window_platform; | |
48 animone::ExecutablePlatform executable_platform; | |
49 } State; | |
50 | |
51 static size_t GetIndentation(const char *line) { | |
52 return strcspn(line, "\t"); | |
53 } | |
54 | |
55 static int HandleIndentation(const size_t current, const std::vector<animone::Player>& players, State *state) { | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
56 // Each state has a definitive expected indentation |
32 | 57 size_t expected; |
58 | |
59 switch (state->state) { | |
60 default: | |
61 case STATENAME_EXPECTPLAYERNAME: | |
62 expected = 0; | |
63 break; | |
64 case STATENAME_EXPECTSECTION: | |
65 expected = 1; | |
66 break; | |
67 case STATENAME_EXPECTWINDOWPLATFORM: | |
68 case STATENAME_EXPECTEXECUTABLEPLATFORM: | |
69 case STATENAME_EXPECTSTRATEGY: | |
70 case STATENAME_EXPECTTYPE: | |
71 expected = 2; | |
72 break; | |
73 case STATENAME_EXPECTWINDOW: | |
74 case STATENAME_EXPECTEXECUTABLE: | |
75 case STATENAME_EXPECTWINDOWTITLE: | |
76 expected = 3; | |
77 break; | |
78 } | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
79 |
21
973734ebd2be
dep/animone: REFACTOR ALL THE THINGS
Paper <paper@paper.us.eu.org>
parents:
14
diff
changeset
|
80 if (current > expected) { |
973734ebd2be
dep/animone: REFACTOR ALL THE THINGS
Paper <paper@paper.us.eu.org>
parents:
14
diff
changeset
|
81 std::cerr << "animone: excessive indentation found" << std::endl; |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
82 return false; // Disallow excessive indentation |
21
973734ebd2be
dep/animone: REFACTOR ALL THE THINGS
Paper <paper@paper.us.eu.org>
parents:
14
diff
changeset
|
83 } |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
84 |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
85 if (current < expected) { |
32 | 86 StateName name; |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
87 |
32 | 88 switch (current) { |
89 case 0: name = STATENAME_EXPECTPLAYERNAME; break; | |
90 default: | |
91 case 1: name = STATENAME_EXPECTSECTION; break; | |
92 case 2: | |
93 switch (state->state) { | |
94 case STATENAME_EXPECTWINDOW: name = STATENAME_EXPECTWINDOWPLATFORM; break; | |
95 case STATENAME_EXPECTEXECUTABLE: name = STATENAME_EXPECTEXECUTABLEPLATFORM; break; | |
96 default: return 0; | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
97 } |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
98 break; |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
99 } |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
100 |
32 | 101 switch (state->state) { |
102 case STATENAME_EXPECTWINDOW: | |
103 if (players.back().windows.empty()) | |
104 return 0; | |
105 state->state = name; | |
106 break; | |
107 case STATENAME_EXPECTEXECUTABLE: | |
108 if (players.back().executables.empty()) | |
109 return 0; | |
110 state->state = name; | |
111 break; | |
112 case STATENAME_EXPECTSTRATEGY: | |
113 if (players.back().strategies.empty()) | |
114 return 0; | |
115 state->state = name; | |
116 break; | |
117 case STATENAME_EXPECTTYPE: | |
118 state->state = name; | |
119 break; | |
120 case STATENAME_EXPECTWINDOWTITLE: | |
121 return 0; | |
122 default: | |
123 break; // ??? | |
124 } | |
125 } | |
126 | |
127 return 1; | |
128 } | |
129 | |
130 bool HandleState(char *line, std::vector<animone::Player>& players, State *state) { | |
131 switch (state->state) { | |
132 case STATENAME_EXPECTPLAYERNAME: | |
133 players.push_back(animone::Player()); | |
134 players.back().name = line; | |
135 state->state = STATENAME_EXPECTSECTION; | |
136 break; | |
137 | |
138 case STATENAME_EXPECTSECTION: | |
139 animone_internal_util_TrimRight(line, ":"); | |
140 | |
141 switch (crcn32b((unsigned char *)line, 11)) { // max: "executables" | |
142 case 0xe3e7859b: state->state = STATENAME_EXPECTWINDOWPLATFORM; break; // "windows" | |
143 case 0x6cdf7147: state->state = STATENAME_EXPECTEXECUTABLEPLATFORM; break; // "executables" | |
144 case 0x611f2213: state->state = STATENAME_EXPECTSTRATEGY; break; // "strategies" | |
145 case 0x8cde5729: state->state = STATENAME_EXPECTTYPE; break; // "type" | |
146 default: return 0; | |
147 } | |
148 | |
149 break; | |
150 | |
151 case STATENAME_EXPECTWINDOWPLATFORM: | |
152 animone_internal_util_TrimRight(line, ":"); | |
153 | |
154 switch (crcn32b((unsigned char *)line, 6)) { // max: "quartz" | |
155 case 0x6fe218f0: state->window_platform = animone::WindowPlatform::Quartz; break; // "quartz" | |
156 case 0xb50ba1d1: state->window_platform = animone::WindowPlatform::Win32; break; // "win32" | |
157 case 0x3220e772: state->window_platform = animone::WindowPlatform::X11; break; // "x11" | |
158 default: return 0; | |
159 } | |
160 | |
161 state->state = STATENAME_EXPECTWINDOW; | |
162 break; | |
163 | |
164 case STATENAME_EXPECTEXECUTABLEPLATFORM: | |
165 animone_internal_util_TrimRight(line, ":"); | |
166 | |
167 switch (crcn32b((unsigned char *)line, 6)) { // max: "macosx" | |
168 case 0xe0e30f6e: state->executable_platform = animone::ExecutablePlatform::Posix; break; // "posix" | |
169 case 0xb50ba1d1: state->executable_platform = animone::ExecutablePlatform::Win32; break; // "win32" | |
170 case 0x912ee411: state->executable_platform = animone::ExecutablePlatform::Xnu; break; // "macosx" | |
171 default: return 0; | |
172 } | |
173 | |
174 state->state = STATENAME_EXPECTEXECUTABLE; | |
175 break; | |
176 | |
177 case STATENAME_EXPECTWINDOW: | |
178 players.back().windows[state->window_platform].push_back(line); | |
179 break; | |
180 | |
181 case STATENAME_EXPECTEXECUTABLE: | |
182 players.back().executables[state->executable_platform].push_back(line); | |
183 break; | |
184 | |
185 case STATENAME_EXPECTSTRATEGY: { | |
186 /* XXX PORT: These should be bit flags instead. */ | |
187 animone_internal_util_TrimRight(line, ":"); | |
188 | |
189 animone::Strategy strategy; | |
190 | |
191 switch (crcn32b((unsigned char *)line, 13)) { // max: "ui_automation" | |
192 case 0xfef78b24: strategy = animone::Strategy::WindowTitle; break; // "window_title" | |
193 case 0x4d88605f: strategy = animone::Strategy::OpenFiles; break; // "open_files" | |
194 case 0xdceb02f6: strategy = animone::Strategy::UiAutomation; break; // "ui_automation" | |
195 default: return 0; | |
196 } | |
197 | |
198 players.back().strategies.push_back(strategy); | |
199 | |
200 switch (strategy) { | |
201 case animone::Strategy::WindowTitle: | |
202 state->state = STATENAME_EXPECTWINDOWTITLE; | |
203 break; | |
204 default: | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
205 break; |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
206 } |
32 | 207 break; |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
208 } |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
209 |
32 | 210 case STATENAME_EXPECTTYPE: { |
211 switch (crcn32b((unsigned char *)line, 13)) { // max: "ui_automation" | |
212 case 0xe35e00df: players.back().type = animone::PlayerType::Default; break; // "default" | |
213 case 0x32bca1a4: players.back().type = animone::PlayerType::WebBrowser; break; // "web_browser" | |
214 default: return 0; | |
215 } | |
216 | |
217 break; | |
218 } | |
219 | |
220 case STATENAME_EXPECTWINDOWTITLE: | |
221 players.back().window_title_format = line; | |
222 state->state = STATENAME_EXPECTSTRATEGY; | |
223 break; | |
224 } | |
225 | |
226 return 1; | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
227 } |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
228 |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
229 //////////////////////////////////////////////////////////////////////////////// |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
230 |
32 | 231 int animone_ParsePlayersData(const char *data, std::vector<animone::Player>& players) { |
232 if (!data || !*data) | |
233 return 0; | |
234 | |
235 const char *ptr, *next; | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
236 |
32 | 237 State state; |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
238 |
32 | 239 int ln; |
240 for (ln = 0, ptr = data; ptr; ln++, ptr = next) { | |
241 next = strchr(ptr, '\n'); | |
242 | |
243 const size_t len = (next) ? (next - ptr) : strlen(ptr); | |
244 if (!len) | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
245 continue; // Ignore empty lines |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
246 |
32 | 247 char *line = (char *)malloc(len + 1); |
248 if (!line) | |
249 return 0; | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
250 |
32 | 251 memcpy(line, ptr, len); |
252 line[len] = '\0'; | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
253 |
32 | 254 size_t indentation = GetIndentation(line); |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
255 |
32 | 256 animone_internal_util_TrimLeft(line, "\t"); |
257 animone_internal_util_TrimRight(line, "\n\r"); | |
258 | |
259 if (!*line || *line == '#') { | |
260 free(line); | |
261 continue; | |
21
973734ebd2be
dep/animone: REFACTOR ALL THE THINGS
Paper <paper@paper.us.eu.org>
parents:
14
diff
changeset
|
262 } |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
263 |
32 | 264 if (!HandleIndentation(indentation, players, &state)) { |
265 fprintf(stderr, "animone: indentation: failed on line %d\n", ln); | |
266 free(line); | |
267 return 0; | |
268 } | |
269 | |
270 if (!HandleState(line, players, &state)) { | |
271 fprintf(stderr, "animone: state: failed on line %d\n", ln); | |
272 free(line); | |
273 return 0; | |
21
973734ebd2be
dep/animone: REFACTOR ALL THE THINGS
Paper <paper@paper.us.eu.org>
parents:
14
diff
changeset
|
274 } |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
275 } |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
276 |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
277 return !players.empty(); |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
278 } |
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
279 |
32 | 280 int animone_ParsePlayersFile(const char *path, std::vector<animone::Player>& players) { |
281 char *data; | |
282 | |
283 if (!animone_internal_util_ReadFile(path, &data, NULL)) | |
284 return 0; | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
285 |
32 | 286 int x = animone_ParsePlayersData(data, players); |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
287 |
32 | 288 free(data); |
289 | |
290 return x; | |
14
27b988a1048c
*: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents:
0
diff
changeset
|
291 } |