32 template <
typename CharPo
interType>
33 class OSCPatternMatcherImpl
35 using CharPtr = CharPointerType;
44 auto c = pattern.getAndAdvance();
66 if (target ==
targetEnd || c != target.getAndAdvance())
107 auto c = pattern.getAndAdvance();
131 static bool matchStringSet (
const StringArray& set, CharPtr pattern,
137 for (
auto& str : set)
138 if (str.getCharPointer().compareUpTo (target, str.length()) == 0)
157 auto c = pattern.getAndAdvance();
227 CharPtr , CharPtr target, CharPtr
targetEnd)
232 auto rangeStart = set.getLast();
233 auto rangeEnd = pattern.getAndAdvance();
241 if (rangeEnd ==
',' || rangeEnd ==
'{' || rangeEnd ==
'}' || set.size() == 0)
244 while (rangeEnd > rangeStart)
245 set.add (++rangeStart);
252 static bool matchOscPattern (
const String& pattern,
const String& target)
254 return OSCPatternMatcherImpl<String::CharPointerType>::match (pattern.getCharPointer(),
255 pattern.getCharPointer().findTerminatingNull(),
256 target.getCharPointer(),
257 target.getCharPointer().findTerminatingNull());
261 template <
typename OSCAddressType>
struct OSCAddressTokeniserTraits;
262 template <>
struct OSCAddressTokeniserTraits<OSCAddress> {
static const char*
getDisallowedChars() {
return " #*,?/[]{}"; } };
263 template <>
struct OSCAddressTokeniserTraits<OSCAddressPattern> {
static const char*
getDisallowedChars() {
return " #/"; } };
266 template <
typename OSCAddressType>
267 struct OSCAddressTokeniser
274 return c >=
' ' && c <=
'~';
279 return CharPointer_ASCII (Traits::getDisallowedChars()).indexOf (c,
false) >= 0;
284 for (
auto charPtr =
string.getCharPointer(); !
charPtr.isEmpty();)
286 auto c =
charPtr.getAndAdvance();
296 static StringArray
tokenise (
const String& address)
298 if (address.isEmpty())
299 throw OSCFormatError (
"OSC format error: address string cannot be empty.");
301 if (! address.startsWithChar (
'/'))
302 throw OSCFormatError (
"OSC format error: address string must start with a forward slash.");
304 StringArray oscSymbols;
305 oscSymbols.addTokens (address,
"/", StringRef());
306 oscSymbols.removeEmptyStrings (
false);
308 for (
auto&
token : oscSymbols)
310 throw OSCFormatError (
"OSC format error: encountered characters not allowed in address string.");
321 asString (address.trimCharactersAtEnd (
"/"))
327 asString (
String (address).trimCharactersAtEnd (
"/"))
334 return asString ==
other.asString;
339 return ! operator== (
other);
351 asString (address.trimCharactersAtEnd (
"/")),
352 wasInitialisedWithWildcards (asString.containsAnyOf (
"*?{}[]"))
359 asString (
String (address).trimCharactersAtEnd (
"/")),
360 wasInitialisedWithWildcards (asString.containsAnyOf (
"*?{}[]"))
367 return asString ==
other.asString;
372 return ! operator== (
other);
378 if (! containsWildcards())
379 return asString == address.asString;
381 if (oscSymbols.size() != address.oscSymbols.size())
384 for (
int i = 0; i < oscSymbols.size(); ++i)
409 void runTest()
override
411 beginTest (
"construction and parsing");
423 expectThrowsType (OSCAddress (
"/notallowedchar}andsomemorechars"), OSCFormatError);
425 expectThrowsType (OSCAddress (
"/nonprintableasciicharacter\t"), OSCFormatError);
436 beginTest (
"conversion to/from String");
438 OSCAddress address (
"/this/is/a/very/long/address/");
439 expectEquals (address.toString(), String (
"/this/is/a/very/long/address"));
455 void runTest()
override
457 beginTest (
"construction and parsing");
462 expectThrowsType (OSCAddressPattern (
"/notallowedchar#andsomemorechars"), OSCFormatError);
464 expectThrowsType (OSCAddressPattern (
"/nonprintableasciicharacter\t"), OSCFormatError);
471 expectDoesNotThrow (OSCAddressPattern (
"/allowedprintablecharacters!$%&()+-.:;<=>@^_`|~"));
475 beginTest (
"construction and parsing - with wildcards");
484 beginTest (
"construction and parsing - with match expressions");
501 beginTest (
"equality comparison");
504 OSCAddressPattern lhs (
"/test/1");
505 OSCAddressPattern rhs (
"/test/1");
507 expect (! (lhs != rhs));
510 OSCAddressPattern lhs (
"/test/1");
511 OSCAddressPattern rhs (
"/test/1/");
513 expect (! (lhs != rhs));
516 OSCAddressPattern lhs (
"/test/1");
517 OSCAddressPattern rhs (
"/test/2");
518 expect (! (lhs == rhs));
523 beginTest (
"basic string matching");
529 OSCAddressPattern pattern (
"/foo/bar");
530 expect (! pattern.containsWildcards());
532 OSCAddress address (
"/foo/bar");
533 expect (pattern.matches (address));
536 OSCAddressPattern pattern (
"/foo/bar/");
537 expect (! pattern.containsWildcards());
539 OSCAddress address (
"/foo/bar");
540 expect (pattern.matches (address));
543 OSCAddressPattern pattern (
"/");
544 expect (! pattern.containsWildcards());
546 OSCAddress address (
"/");
547 expect (pattern.matches (address));
550 OSCAddressPattern pattern (
"/foo/bar");
551 expect (! pattern.containsWildcards());
553 expect (! pattern.matches (OSCAddress (
"/foo/baz")));
554 expect (! pattern.matches (OSCAddress (
"/foo/bar/baz")));
555 expect (! pattern.matches (OSCAddress (
"/foo")));
559 beginTest (
"string matching with wildcards");
561 OSCAddressPattern pattern (
"/*/*put/slider[0-9]");
562 expect (pattern.containsWildcards());
564 expect (pattern.matches (OSCAddress (
"/mypatch/input/slider0")));
565 expect (pattern.matches (OSCAddress (
"/myotherpatch/output/slider9")));
566 expect (! pattern.matches (OSCAddress (
"/myotherpatch/output/slider10")));
567 expect (! pattern.matches (OSCAddress (
"/output/slider9")));
568 expect (! pattern.matches (OSCAddress (
"/myotherpatch/output/slider9/position")));
571 beginTest (
"conversion to/from String");
574 OSCAddressPattern
ap (
"/this/is/a/very/long/address/");
575 expectEquals (
ap.toString(), String (
"/this/is/a/very/long/address"));
578 OSCAddressPattern
ap (
"/*/*put/{fader,slider,knob}[0-9]/ba?/");
579 expectEquals (
ap.toString(), String (
"/*/*put/{fader,slider,knob}[0-9]/ba?"));
596 void runTest()
override
598 beginTest (
"basic string matching");
608 beginTest (
"string matching with '?' wildcard");
620 beginTest (
"string matching with '*' wildcard");
635 expect (
matchOscPattern (
"*reallyreallylongstringstringstring",
"reallyreallylongstringstringstrNOT"
636 "reallyreallylongstringstringstrNOT"
637 "reallyreallylongstringstringstrNOT"
638 "reallyreallylongstringstringstrNOT"
639 "reallyreallylongstringstringstrNOT"
640 "reallyreallylongstringstringstring"));
643 beginTest (
"string matching with '{..., ...}' pattern");
656 expect (
matchOscPattern (
"aaa{bc,def,ghij,klmnopqrstu}eee",
"aaaghijeee"));
675 beginTest (
"string matching with '[...]' pattern");
697 expect (
matchOscPattern (
"foo[abc]foo[defgh]foo[i]foo[]foo",
"foobfoohfooifoofoo"));
722 expect (!
matchOscPattern (
"foo[ae-iko-uz1-8D-FX]b[a-a]r",
"foobbar"));
723 expect (!
matchOscPattern (
"foo[ae-iko-uz1-8D-FX]b[aaaa-aaaa-aaaa]r",
"foodbar"));
748 expect (!
matchOscPattern (
"foo[ae-iko-uz1-8D-FX]ba[Rr]",
"fooFXbar"));
781 beginTest (
"string matching combining patterns");
783 expect (
matchOscPattern (
"*ea*ll[y-z0-9X-Zvwx]??m[o-q]l[e]x{fat,mat,pat}te{}r*?",
"reallycomplexpattern"));
bool matches(const OSCAddress &address) const noexcept
Checks if the OSCAddressPattern matches an OSC address with the wildcard rules defined by the OpenSou...
bool operator!=(const OSCAddressPattern &other) const noexcept
Compares two OSCAddressPattern objects.
OSCAddressPattern(const String &address)
Constructs a new OSCAddressPattern from a String.
bool operator==(const OSCAddressPattern &other) const noexcept
Compares two OSCAddressPattern objects.
String toString() const noexcept
Converts the OSCAddressPattern to a String.
String toString() const noexcept
Converts the OSCAddress to a String.
bool operator==(const OSCAddress &other) const noexcept
Compares two OSCAddress objects.
OSCAddress(const String &address)
Constructs a new OSCAddress from a String.
bool operator!=(const OSCAddress &other) const noexcept
Compares two OSCAddress objects.
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Creates a String from a UTF-8 encoded buffer.
This is a base class for classes that perform a unit test.
#define expectDoesNotThrow(expr)
Checks that the result of an expression does not throw an exception.
#define expectThrowsType(expr, type)
Checks that the result of an expression throws an exception of a certain type.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...