diff --git a/OSC2AHK/dllmain.cpp b/OSC2AHK/dllmain.cpp index 5c4a48d..f38e740 100644 --- a/OSC2AHK/dllmain.cpp +++ b/OSC2AHK/dllmain.cpp @@ -219,6 +219,136 @@ bool isMatchingOscType(unsigned int msgType, unsigned int listenerTypeField) return (listenerTypeField & msgType); } +/* Checks if an incoming OSC messages address matches a given pattern. +* Also handles OSC wildcards! */ +bool isMatchingOSCAddress(const char* address, const char* pattern) +{ + //If no wildcards in pattern, do a simple strcmp to save time + if (!containsOscWildcard(pattern)) + { + if (strcmp(address, pattern) == 0) return true; + else return false; + } + + std::string chars; + + while (*address != '\0' && *pattern != '\0') + { + switch (*pattern) + { + case '?': //exactly one character + if (*address == '/') return false; //'?' does not match beyond '/' + address++; + pattern++; + break; + case '*': //zero or more chars + pattern++; + if (isMatchingOSCAddress(address, pattern)) return true; //'*' matches "no char" + while (*address != '\0' && *address != '/') + { //shift address one char and check again (recursion) + address++; + if (isMatchingOSCAddress(address, pattern)) return true; + } + return false; + break; + case '[': //Match one character from list (or range of) chars like [asdf] or [a-f] or [!0-9] + pattern++; + while (*pattern != '\0' && + *pattern != ']' && + *pattern != '/') + { + if (*pattern == '-') //range of chars + { + pattern++; + char c = chars.back() + 1; + if (*pattern == ']' || *pattern == '/' || *pattern == '\0') c = *pattern; + while (c != *pattern) + { + chars.push_back(c); + c++; + } + } + chars.push_back(*pattern); + pattern++; + } + if (chars.at(0) == '!') //negated list or range of chars + { + chars.erase(chars.begin()); + if (chars.find(*address) != std::string::npos) return false; + } + else if (chars.find(*address) == std::string::npos) return false; + chars.clear(); + if (*pattern == ']') pattern++; + address++; + break; + case '{': //list of strings (comma separated like {asd,fghj,etc} + bool result; + result = false; + pattern++; + while (!result && + *pattern != '\0' && + *pattern != '}' && + *pattern != '/') + { + while (*pattern != '\0' && + *pattern != ',' && + *pattern != '}' && + *pattern != '/') + { + chars.push_back(*pattern); + pattern++; + } + if (chars.compare(0, chars.length(), address, chars.length()) == 0) + { + result = true; + address += chars.length(); + } + chars.clear(); + pattern++; + } + if (!result) return false; + while (*pattern != '\0' && + *pattern != '}' && + *pattern != '/') + { + pattern++; + } + if (*pattern == '}') pattern++; + break; + default: //Just a character, no wildcard here + if (*pattern == *address) + { + address++; + pattern++; + } + else + { + return false; + } + break; + } + } + + if (*pattern != *address) return false; //Only match if both strings end here. + + return true; //No earlier 'return false' triggered, so we got a match! +} + +bool containsOscWildcard(const char* pattern) +{ + while (*pattern != '\0') + { + if (*pattern == '?' || + *pattern == '*' || + *pattern == '[' || + *pattern == ']' || + *pattern == '{' || + *pattern == '}') return true; + pattern++; + } + return false; +} + int handleOscMsg(const osc::ReceivedMessage& m) { int ret = 0; @@ -241,7 +371,7 @@ int handleOscMsg(const osc::ReceivedMessage& m) for (UINT i = 0; i < listeners.size(); i++) { //Check if incoming OSC address matches current listener entry - if (listeners[i].address.compare(m.AddressPattern()) == 0) //TODO: Implement OSC Pattern Wildcards + if ( isMatchingOSCAddress(m.AddressPattern(), listeners[i].address.c_str()) ) { //Check payload type if (m.ArgumentCount() == 0) { diff --git a/OSC2AHK/dllmain.h b/OSC2AHK/dllmain.h index 471b4e5..f5a108f 100644 --- a/OSC2AHK/dllmain.h +++ b/OSC2AHK/dllmain.h @@ -26,6 +26,8 @@ extern "C" DLLEXPORT int removeListener(LPCSTR address); extern "C" DLLEXPORT char* getStringData(char* targetString, unsigned int targetSize, unsigned int StringID); int handleOscMsg(const osc::ReceivedMessage& m); bool isMatchingOscType(unsigned int msgType, unsigned int listenerTypeField); +bool isMatchingOSCAddress(const char* address, const char* pattern); +bool containsOscWildcard(const char* pattern); unsigned int getOscType(osc::ReceivedMessage::const_iterator arg); void removeStoredString(int stringId); int addStoredString(std::string theString);