Index: compiled/ActiveFilter.cpp |
=================================================================== |
new file mode 100644 |
--- /dev/null |
+++ b/compiled/ActiveFilter.cpp |
@@ -0,0 +1,147 @@ |
+#include "ActiveFilter.h" |
+#include "StringScanner.h" |
+ |
+namespace |
+{ |
+ const std::u16string ProcessDomain(const std::u16string& docDomain, |
+ bool ignoreTrailingDot) |
+ { |
+ size_t len = docDomain.length(); |
+ if (ignoreTrailingDot) |
+ { |
+ for (; len > 0; --len) |
+ { |
+ if (docDomain[len - 1] != u'.') |
+ break; |
+ } |
+ } |
+ |
+ std::u16string domain(docDomain.substr(0, len)); |
+ for (size_t i = 0, l = domain.length(); i < l; ++i) |
+ { |
+ char16_t currChar = domain[i]; |
+ // TODO: This needs to work for non-ASCII as well |
+ if (currChar >= u'a' && currChar <= u'z') |
+ domain[i] = currChar + u'A' - u'a'; |
+ } |
+ return domain; |
+ } |
+ |
+ const std::u16string to_u16string(unsigned int i) |
+ { |
+ std::string str(std::to_string(i)); |
+ std::u16string result(str.length(), u'\0'); |
+ |
+ for (size_t i = 0, l = str.length(); i < l; ++i) |
+ result[i] = str[i]; |
+ return result; |
+ } |
+} |
+ |
+ActiveFilter::ActiveFilter(const std::u16string& text, bool ignoreTrailingDot) |
+ : Filter(text), disabled(false), hitCount(0), lastHit(0), |
+ ignoreTrailingDot(ignoreTrailingDot) |
+{ |
+} |
+ |
+void ActiveFilter::ParseDomains(const std::u16string& str, char16_t separator) |
+{ |
+ StringScanner scanner(str + separator); |
+ size_t start = 0; |
+ bool reverse = false; |
+ bool hasIncludes = false; |
+ while (!scanner.done()) |
+ { |
+ char16_t currChar = scanner.next(); |
+ if (currChar == u'~' && scanner.position() == start) |
+ { |
+ start++; |
+ reverse = true; |
+ } |
+ else if (currChar == separator) |
+ { |
+ if (scanner.position() > start) |
+ { |
+ std::u16string domain( |
+ ProcessDomain(str.substr(start, scanner.position() - start), |
+ ignoreTrailingDot) |
+ ); |
+ domains[domain] = !reverse; |
+ if (!reverse) |
+ hasIncludes = true; |
+ } |
+ start = scanner.position() + 1; |
+ reverse = false; |
+ } |
+ } |
+ domains[u""] = !hasIncludes; |
+} |
+ |
+ |
+bool ActiveFilter::IsActiveOnDomain(const std::u16string& docDomain, |
+ const std::u16string& sitekey) |
+{ |
+ if (!sitekeys.empty() && sitekeys.find(sitekey) == sitekeys.end()) |
+ return false; |
+ |
+ // If no domains are set the rule matches everywhere |
+ if (domains.empty()) |
+ return true; |
+ |
+ // If the document has no host name, match only if the filter isn't restricted |
+ // to specific domains |
+ if (docDomain.empty()) |
+ return domains[u""]; |
+ |
+ std::u16string domain(ProcessDomain(docDomain, ignoreTrailingDot)); |
+ while (true) |
+ { |
+ auto it = domains.find(domain); |
+ if (it != domains.end()) |
+ return it->second; |
+ |
+ size_t nextDot = domain.find(u'.'); |
+ if (nextDot == domain.npos) |
+ break; |
+ domain = domain.substr(nextDot + 1); |
+ } |
+ return domains[u""]; |
+} |
+ |
+bool ActiveFilter::IsActiveOnlyOnDomain(const std::u16string& docDomain) |
+{ |
+ if (domains.empty() || docDomain.empty() || domains[u""]) |
+ return false; |
+ |
+ std::u16string domain(ProcessDomain(docDomain, ignoreTrailingDot)); |
+ for (auto it = domains.begin(); it != domains.end(); ++it) |
+ { |
+ if (!it->second || it->first == domain) |
+ continue; |
+ |
+ size_t len1 = it->first.length(); |
+ size_t len2 = domain.length(); |
+ if (len1 > len2 && it->first.rfind(u"." + domain) == len1 - len2 - 1) |
+ continue; |
+ |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool ActiveFilter::IsGeneric() |
+{ |
+ return (sitekeys.empty() && (domains.empty() || domains[u""])); |
+} |
+ |
+const std::u16string ActiveFilter::Serialize() |
+{ |
+ std::u16string result(Filter::Serialize()); |
+ if (disabled) |
+ result += u"disabled=true\n"; |
+ if (hitCount) |
+ result += u"hitCount=" + to_u16string(hitCount) + u"\n"; |
+ if (lastHit) |
+ result += u"lastHit=" + to_u16string(lastHit) + u"\n"; |
+ return result; |
+} |