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 } |
