hydra_cfg.c (2708B)
1 // Hydra driver configuration reader — see hydra_cfg.h. 2 // 3 // Deliberately dependency-free: a tiny hand-rolled scan for the first device's "name" 4 // string, so the driver vendors no JSON library and stays trivial to audit. The manifest 5 // is small and written by us, so we don't need a full parser — just locate 6 // "devices" : [ { ... "name" : "VALUE" ... } ... ] 7 // and extract VALUE (handling \" and \\ escapes). 8 9 #include "hydra_cfg.h" 10 #include <stdio.h> 11 #include <string.h> 12 13 // Overridable at compile time for host-side testing; defaults to the real system path. 14 #ifndef HYDRA_MANIFEST_PATH 15 #define HYDRA_MANIFEST_PATH "/Library/Application Support/hydra/devices.json" 16 #endif 17 18 // Find the next `"key"` token at or after `p`, return a pointer just past the closing quote 19 // of the key (i.e. at the ':' region), or NULL. Only matches the key name, not values. 20 static const char *find_key(const char *p, const char *end, const char *key) { 21 size_t klen = strlen(key); 22 for (; p + klen + 1 < end; p++) { 23 if (*p == '"' && (size_t)(end - p) > klen + 1 && 24 strncmp(p + 1, key, klen) == 0 && p[1 + klen] == '"') { 25 return p + 1 + klen + 1; // just past the closing quote of the key 26 } 27 } 28 return NULL; 29 } 30 31 // From `p`, skip to the next string value's opening quote and copy it (unescaped) into out. 32 // Returns 1 on success. 33 static int copy_next_string(const char *p, const char *end, char *out, int cap) { 34 while (p < end && *p != '"') p++; // find opening quote of the value 35 if (p >= end) return 0; 36 p++; // past opening quote 37 int n = 0; 38 while (p < end && n < cap - 1) { 39 char c = *p; 40 if (c == '\\' && p + 1 < end) { // escape: copy the next char verbatim (\" \\ etc.) 41 out[n++] = p[1]; 42 p += 2; 43 continue; 44 } 45 if (c == '"') { // unescaped quote ⇒ end of value 46 break; 47 } 48 out[n++] = c; 49 p++; 50 } 51 out[n] = '\0'; 52 return n > 0; 53 } 54 55 int hydra_cfg_device_name(char *out_name, int cap) { 56 if (!out_name || cap <= 0) return 0; 57 58 FILE *f = fopen(HYDRA_MANIFEST_PATH, "rb"); 59 if (!f) return 0; 60 61 char buf[8192]; 62 size_t len = fread(buf, 1, sizeof(buf) - 1, f); 63 fclose(f); 64 if (len == 0) return 0; 65 buf[len] = '\0'; 66 67 const char *end = buf + len; 68 // Anchor to the devices array so we read a device's name, not some top-level field. 69 const char *p = find_key(buf, end, "devices"); 70 if (!p) p = buf; // tolerate a flat shape too 71 p = find_key(p, end, "name"); 72 if (!p) return 0; 73 return copy_next_string(p, end, out_name, cap); 74 }