Index: compiled/ElemHideBase.cpp |
=================================================================== |
new file mode 100644 |
--- /dev/null |
+++ b/compiled/ElemHideBase.cpp |
@@ -0,0 +1,155 @@ |
+#include "ElemHideBase.h" |
+#include "CSSPropertyFilter.h" |
+#include "StringScanner.h" |
+ |
+namespace |
+{ |
+ void NormalizeWhitespace(String& text, String::size_type& domainsEnd, |
+ String::size_type& selectorStart) |
+ { |
+ // For element hiding filters we only want to remove spaces preceding the |
+ // selector part. The positions we've determined already have to be adjusted |
+ // accordingly. |
+ |
+ String::size_type delta = 0; |
+ String::size_type len = text.length(); |
+ |
+ // The first character is guaranteed to be a non-space, the string has been |
+ // trimmed earlier. |
+ for (String::size_type pos = 1; pos < len; pos++) |
+ { |
+ if (pos == domainsEnd) |
+ domainsEnd -= delta; |
+ |
+ // Only spaces before selectorStart position should be removed. |
+ if (pos < selectorStart && text[pos] == ' ') |
+ delta++; |
+ else |
+ text[pos - delta] = text[pos]; |
+ } |
+ selectorStart -= delta; |
+ |
+ text.reset(text, 0, len - delta); |
+ } |
+} |
+ |
+ElemHideBase::ElemHideBase(const String& text, const ElemHideBaseData& data) |
+ : ActiveFilter(text, false), ElemHideBaseData(data) |
+{ |
+ if (HasDomains()) |
+ ParseDomains(GetDomainsSource(mText), u','); |
+} |
+ |
+Filter::Type ElemHideBase::Parse(String& text, ElemHideData& data) |
+{ |
+ StringScanner scanner(text); |
+ |
+ // Domains part |
+ bool seenSpaces = false; |
+ while (!scanner.done()) |
+ { |
+ String::value_type next = scanner.next(); |
+ if (next == u'#') |
+ { |
+ data.mDomainsEnd = scanner.position(); |
+ break; |
+ } |
+ |
+ switch (next) |
+ { |
+ case u'/': |
+ case u'*': |
+ case u'|': |
+ case u'@': |
+ case u'"': |
+ case u'!': |
+ return Type::UNKNOWN; |
+ case u' ': |
+ seenSpaces = true; |
+ break; |
+ } |
+ } |
+ |
+ seenSpaces |= scanner.skip(u' '); |
+ bool exception = scanner.skipOne(u'@'); |
+ if (exception) |
+ seenSpaces |= scanner.skip(u' '); |
+ |
+ String::value_type next = scanner.next(); |
+ if (next != u'#') |
+ return Type::UNKNOWN; |
+ |
+ // Selector part |
+ |
+ // Selector shouldn't be empty |
+ seenSpaces |= scanner.skip(u' '); |
+ if (scanner.done()) |
+ return Type::UNKNOWN; |
+ |
+ data.mSelectorStart = scanner.position() + 1; |
+ while (!scanner.done()) |
+ { |
+ switch (scanner.next()) |
+ { |
+ case u'{': |
+ case u'}': |
+ return Type::UNKNOWN; |
+ } |
+ } |
+ |
+ // We are done validating, now we can normalize whitespace and the domain part |
+ if (seenSpaces) |
+ NormalizeWhitespace(text, data.mDomainsEnd, data.mSelectorStart); |
+ ToLower(text, 0, data.mDomainsEnd); |
+ |
+ if (exception) |
+ return Type::ELEMHIDEEXCEPTION; |
+ |
+ do |
+ { |
+ // Is this a CSS property rule maybe? |
+ String searchString(u"[-abp-properties="_str); |
+ data.mPrefixEnd = text.find(searchString, data.mSelectorStart); |
+ if (data.mPrefixEnd == text.npos || |
+ data.mPrefixEnd + searchString.length() + 1 >= text.length()) |
+ { |
+ break; |
+ } |
+ |
+ data.mRegexpStart = data.mPrefixEnd + searchString.length() + 1; |
+ char16_t quotation = text[data.mRegexpStart - 1]; |
+ if (quotation != u'\'' && quotation != u'"') |
+ break; |
+ |
+ data.mRegexpEnd = text.find(quotation, data.mRegexpStart); |
+ if (data.mRegexpEnd == text.npos || data.mRegexpEnd + 1 >= text.length() || |
+ text[data.mRegexpEnd + 1] != u']') |
+ { |
+ break; |
+ } |
+ |
+ data.mSuffixStart = data.mRegexpEnd + 2; |
+ return Type::CSSPROPERTY; |
+ } while (false); |
+ |
+ return Type::ELEMHIDE; |
+} |
+ |
+String ElemHideBase::GetSelectorDomain() const |
+{ |
+ /* TODO this is inefficient */ |
+ String result; |
+ if (mDomains) |
+ { |
+ for (auto it = mDomains->begin(); it != mDomains->end(); ++it) |
+ { |
+ if (it->second && !it->first.empty()) |
+ { |
+ if (!result.empty()) |
+ result.append(u','); |
+ result.append(it->first); |
+ } |
+ } |
+ } |
+ return std::move(result.ensure_own_buffer()); |
+} |