Mercurial > libanimone
view 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 |
line wrap: on
line source
#include "animone/player.h" #include "animone/util.h" #include <map> #include <sstream> #include <string> #include <vector> #include <iostream> #include <string.h> #include <stdio.h> // simple crc32-hash function, derived from Hacker's Delight // and expects a C-string as input. // `n` should be the amount of the largest expected value of // the hash. static inline constexpr uint32_t crcn32b(unsigned char *message, size_t n) { uint32_t crc = 0xFFFFFFFF; size_t i = 0, j = 0; for (i = 0; message[i] && i < n; i++) { crc = crc ^ message[i]; for (j = 0; j < 8; j++) crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1)); } return ~crc; } typedef enum StateName { STATENAME_EXPECTPLAYERNAME = 0, STATENAME_EXPECTSECTION, STATENAME_EXPECTWINDOWPLATFORM, STATENAME_EXPECTEXECUTABLEPLATFORM, STATENAME_EXPECTWINDOW, STATENAME_EXPECTEXECUTABLE, STATENAME_EXPECTSTRATEGY, STATENAME_EXPECTTYPE, STATENAME_EXPECTWINDOWTITLE, } StateName; typedef struct State { StateName state; animone::WindowPlatform window_platform; animone::ExecutablePlatform executable_platform; } State; static size_t GetIndentation(const char *line) { return strcspn(line, "\t"); } static int HandleIndentation(const size_t current, const std::vector<animone::Player>& players, State *state) { // Each state has a definitive expected indentation size_t expected; switch (state->state) { default: case STATENAME_EXPECTPLAYERNAME: expected = 0; break; case STATENAME_EXPECTSECTION: expected = 1; break; case STATENAME_EXPECTWINDOWPLATFORM: case STATENAME_EXPECTEXECUTABLEPLATFORM: case STATENAME_EXPECTSTRATEGY: case STATENAME_EXPECTTYPE: expected = 2; break; case STATENAME_EXPECTWINDOW: case STATENAME_EXPECTEXECUTABLE: case STATENAME_EXPECTWINDOWTITLE: expected = 3; break; } if (current > expected) { std::cerr << "animone: excessive indentation found" << std::endl; return false; // Disallow excessive indentation } if (current < expected) { StateName name; switch (current) { case 0: name = STATENAME_EXPECTPLAYERNAME; break; default: case 1: name = STATENAME_EXPECTSECTION; break; case 2: switch (state->state) { case STATENAME_EXPECTWINDOW: name = STATENAME_EXPECTWINDOWPLATFORM; break; case STATENAME_EXPECTEXECUTABLE: name = STATENAME_EXPECTEXECUTABLEPLATFORM; break; default: return 0; } break; } switch (state->state) { case STATENAME_EXPECTWINDOW: if (players.back().windows.empty()) return 0; state->state = name; break; case STATENAME_EXPECTEXECUTABLE: if (players.back().executables.empty()) return 0; state->state = name; break; case STATENAME_EXPECTSTRATEGY: if (players.back().strategies.empty()) return 0; state->state = name; break; case STATENAME_EXPECTTYPE: state->state = name; break; case STATENAME_EXPECTWINDOWTITLE: return 0; default: break; // ??? } } return 1; } bool HandleState(char *line, std::vector<animone::Player>& players, State *state) { switch (state->state) { case STATENAME_EXPECTPLAYERNAME: players.push_back(animone::Player()); players.back().name = line; state->state = STATENAME_EXPECTSECTION; break; case STATENAME_EXPECTSECTION: animone_internal_util_TrimRight(line, ":"); switch (crcn32b((unsigned char *)line, 11)) { // max: "executables" case 0xe3e7859b: state->state = STATENAME_EXPECTWINDOWPLATFORM; break; // "windows" case 0x6cdf7147: state->state = STATENAME_EXPECTEXECUTABLEPLATFORM; break; // "executables" case 0x611f2213: state->state = STATENAME_EXPECTSTRATEGY; break; // "strategies" case 0x8cde5729: state->state = STATENAME_EXPECTTYPE; break; // "type" default: return 0; } break; case STATENAME_EXPECTWINDOWPLATFORM: animone_internal_util_TrimRight(line, ":"); switch (crcn32b((unsigned char *)line, 6)) { // max: "quartz" case 0x6fe218f0: state->window_platform = animone::WindowPlatform::Quartz; break; // "quartz" case 0xb50ba1d1: state->window_platform = animone::WindowPlatform::Win32; break; // "win32" case 0x3220e772: state->window_platform = animone::WindowPlatform::X11; break; // "x11" default: return 0; } state->state = STATENAME_EXPECTWINDOW; break; case STATENAME_EXPECTEXECUTABLEPLATFORM: animone_internal_util_TrimRight(line, ":"); switch (crcn32b((unsigned char *)line, 6)) { // max: "macosx" case 0xe0e30f6e: state->executable_platform = animone::ExecutablePlatform::Posix; break; // "posix" case 0xb50ba1d1: state->executable_platform = animone::ExecutablePlatform::Win32; break; // "win32" case 0x912ee411: state->executable_platform = animone::ExecutablePlatform::Xnu; break; // "macosx" default: return 0; } state->state = STATENAME_EXPECTEXECUTABLE; break; case STATENAME_EXPECTWINDOW: players.back().windows[state->window_platform].push_back(line); break; case STATENAME_EXPECTEXECUTABLE: players.back().executables[state->executable_platform].push_back(line); break; case STATENAME_EXPECTSTRATEGY: { /* XXX PORT: These should be bit flags instead. */ animone_internal_util_TrimRight(line, ":"); animone::Strategy strategy; switch (crcn32b((unsigned char *)line, 13)) { // max: "ui_automation" case 0xfef78b24: strategy = animone::Strategy::WindowTitle; break; // "window_title" case 0x4d88605f: strategy = animone::Strategy::OpenFiles; break; // "open_files" case 0xdceb02f6: strategy = animone::Strategy::UiAutomation; break; // "ui_automation" default: return 0; } players.back().strategies.push_back(strategy); switch (strategy) { case animone::Strategy::WindowTitle: state->state = STATENAME_EXPECTWINDOWTITLE; break; default: break; } break; } case STATENAME_EXPECTTYPE: { switch (crcn32b((unsigned char *)line, 13)) { // max: "ui_automation" case 0xe35e00df: players.back().type = animone::PlayerType::Default; break; // "default" case 0x32bca1a4: players.back().type = animone::PlayerType::WebBrowser; break; // "web_browser" default: return 0; } break; } case STATENAME_EXPECTWINDOWTITLE: players.back().window_title_format = line; state->state = STATENAME_EXPECTSTRATEGY; break; } return 1; } //////////////////////////////////////////////////////////////////////////////// int animone_ParsePlayersData(const char *data, std::vector<animone::Player>& players) { if (!data || !*data) return 0; const char *ptr, *next; State state; int ln; for (ln = 0, ptr = data; ptr; ln++, ptr = next) { next = strchr(ptr, '\n'); const size_t len = (next) ? (next - ptr) : strlen(ptr); if (!len) continue; // Ignore empty lines char *line = (char *)malloc(len + 1); if (!line) return 0; memcpy(line, ptr, len); line[len] = '\0'; size_t indentation = GetIndentation(line); animone_internal_util_TrimLeft(line, "\t"); animone_internal_util_TrimRight(line, "\n\r"); if (!*line || *line == '#') { free(line); continue; } if (!HandleIndentation(indentation, players, &state)) { fprintf(stderr, "animone: indentation: failed on line %d\n", ln); free(line); return 0; } if (!HandleState(line, players, &state)) { fprintf(stderr, "animone: state: failed on line %d\n", ln); free(line); return 0; } } return !players.empty(); } int animone_ParsePlayersFile(const char *path, std::vector<animone::Player>& players) { char *data; if (!animone_internal_util_ReadFile(path, &data, NULL)) return 0; int x = animone_ParsePlayersData(data, players); free(data); return x; }