namespace NATS.Server.Subscriptions; public static class SubjectMatch { public const char Pwc = '*'; // partial wildcard public const char Fwc = '>'; // full wildcard public const char Sep = '.'; // token separator public static bool IsValidSubject(string subject) { if (string.IsNullOrEmpty(subject)) return false; bool sawFwc = false; int start = 0; for (int i = 0; i <= subject.Length; i++) { if (i == subject.Length || subject[i] == Sep) { int tokenLen = i - start; if (tokenLen == 0 || sawFwc) return false; if (tokenLen == 1) { char c = subject[start]; if (c == Fwc) sawFwc = true; else if (c is ' ' or '\t' or '\n' or '\r' or '\f') return false; } else { for (int j = start; j < i; j++) { char c = subject[j]; if (c is ' ' or '\t' or '\n' or '\r' or '\f') return false; } } start = i + 1; } } return true; } public static bool IsLiteral(string subject) { for (int i = 0; i < subject.Length; i++) { char c = subject[i]; if (c is Pwc or Fwc) { bool atStart = i == 0 || subject[i - 1] == Sep; bool atEnd = i + 1 == subject.Length || subject[i + 1] == Sep; if (atStart && atEnd) return false; } } return true; } public static bool IsValidPublishSubject(string subject) { return IsValidSubject(subject) && IsLiteral(subject); } /// /// Match a literal subject against a pattern that may contain wildcards. /// public static bool MatchLiteral(string literal, string pattern) { int li = 0, pi = 0; while (pi < pattern.Length) { // Get next pattern token int pTokenStart = pi; while (pi < pattern.Length && pattern[pi] != Sep) pi++; int pTokenLen = pi - pTokenStart; if (pi < pattern.Length) pi++; // skip separator // Full wildcard -- matches everything remaining if (pTokenLen == 1 && pattern[pTokenStart] == Fwc) return li < literal.Length; // must have at least one token left // Get next literal token if (li >= literal.Length) return false; int lTokenStart = li; while (li < literal.Length && literal[li] != Sep) li++; int lTokenLen = li - lTokenStart; if (li < literal.Length) li++; // skip separator // Partial wildcard -- matches any single token if (pTokenLen == 1 && pattern[pTokenStart] == Pwc) continue; // Literal comparison if (pTokenLen != lTokenLen) return false; if (string.Compare(literal, lTokenStart, pattern, pTokenStart, pTokenLen, StringComparison.Ordinal) != 0) return false; } return li >= literal.Length; // both exhausted } }