int string_extract_index( const char* path, const char* prefix, int digits, const char* after) { rassert(path != NULL); rassert(digits > 0); if (!string_has_prefix(path, prefix)) return -1; static const char hex_digits[] = "0123456789abcdef"; int prefix_len = 0; if (prefix != NULL) { prefix_len = (int)strlen(prefix); } else { prefix_len = (int)strcspn(path, hex_digits); if (path[prefix_len] == '\0') return -1; } const char* num_s = path + prefix_len; int index = 0; for (int i = 0; i < digits; ++i, ++num_s) { index *= 0x10; if (*num_s == '\0') return -1; char* pos = strchr(hex_digits, *num_s); if (pos == NULL) return -1; index += (int)(pos - hex_digits); } if (string_has_prefix(after, ".") && !string_eq(num_s, after)) return -1; else if ((after != NULL) && string_eq(after, "") && !string_eq(num_s, "")) return -1; else if (!string_has_prefix(num_s, after)) return -1; return index; }
bool Device_set_state_key( const Device* device, Device_states* dstates, const char* key) { assert(device != NULL); assert(dstates != NULL); assert(key != NULL); assert(string_has_prefix(key, "i/") || string_has_prefix(key, "c/")); if (device->dimpl != NULL) { Device_state* dstate = Device_states_get_state( dstates, Device_get_id(device)); return Device_impl_set_state_key(device->dimpl, dstate, key + 2); } return true; }
bool Device_set_key(Device* device, const char* key, Streader* sr) { assert(device != NULL); assert(key != NULL); assert(string_has_prefix(key, "i/") || string_has_prefix(key, "c/")); assert(sr != NULL); if (Streader_is_error_set(sr)) return false; if (!Device_params_parse_value(device->dparams, key, sr)) return false; if (device->dimpl != NULL && !Device_impl_set_key(device->dimpl, key + 2)) { Streader_set_memory_error( sr, "Could not allocate memory for device key %s", key); return false; } return true; }
static int validate_connection_path( Streader* sr, char* str, Connection_level level, Device_port_type type) { rassert(sr != NULL); rassert(str != NULL); rassert(type < DEVICE_PORT_TYPES); if (Streader_is_error_set(sr)) return -1; bool root = true; char* path = str; char* trim_point = str; // Device if (string_has_prefix(str, "au_")) { // TODO: disallow audio unit in more than 2 levels if ((level != CONNECTION_LEVEL_GLOBAL) && (level != CONNECTION_LEVEL_AU)) { Streader_set_error( sr, "Audio unit directory in a deep-level connection: \"%s\"", path); return -1; } root = false; str += strlen("au_"); if (read_index(str) >= KQT_AUDIO_UNITS_MAX) { Streader_set_error( sr, "Invalid audio unit number in the connection: \"%s\"", path); return -1; } str += 2; if (!string_has_prefix(str, "/")) { Streader_set_error( sr, "Missing trailing '/' after the audio unit number" " in the connection: \"%s\"", path); return -1; } ++str; trim_point = str - 1; } else if (string_has_prefix(str, "proc_")) { if (level != CONNECTION_LEVEL_AU) { Streader_set_error( sr, "Processor directory in a root-level connection: \"%s\"", path); return -1; } root = false; str += strlen("proc_"); if (read_index(str) >= KQT_PROCESSORS_MAX) { Streader_set_error( sr, "Invalid processor number in the connection: \"%s\"", path); return -1; } str += 2; if (!string_has_prefix(str, "/")) { Streader_set_error( sr, "Missing trailing '/' after the processor number" " in the connection: \"%s\"", path); return -1; } ++str; if (!string_has_prefix(str, "C/")) { Streader_set_error( sr, "Invalid processor parameter directory" " in the connection: \"%s\"", path); return -1; } str += strlen("C/"); trim_point = str - 1; } // Port if (string_has_prefix(str, "in_") || string_has_prefix(str, "out_")) { if (string_has_prefix(str, "in_") && root && (level != CONNECTION_LEVEL_AU)) { Streader_set_error( sr, "Input ports are not allowed for master: \"%s\"", path); return -1; } if (type == DEVICE_PORT_TYPE_RECV) { bool can_receive = (!root && string_has_prefix(str, "in_")) || (root && string_has_prefix(str, "out_")); if (!can_receive) { Streader_set_error( sr, "Destination port is not for receiving data: \"%s\"", path); return -1; } } else { rassert(type == DEVICE_PORT_TYPE_SEND); bool can_send = (string_has_prefix(str, "out_") && !root) || (string_has_prefix(str, "in_") && root); if (!can_send) { Streader_set_error( sr, "Source port is not for sending data: \"%s\"", path); return -1; } } str += strcspn(str, "_") + 1; int port = read_index(str); if (port >= KQT_DEVICE_PORTS_MAX) { Streader_set_error(sr, "Invalid port number: \"%s\"", path); return -1; } str += 2; if (str[0] != '/' && str[0] != '\0' && str[1] != '\0') { Streader_set_error( sr, "Connection path contains garbage" " after the port specification: \"%s\"", path); return -1; } *trim_point = '\0'; return port; } Streader_set_error(sr, "Invalid connection: \"%s\"", path); return -1; }