| 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(DependentString& 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(DependentString& 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; |
| +} |
| + |
| +OwnedString ElemHideBase::GetSelectorDomain() const |
| +{ |
| + /* TODO this is inefficient */ |
| + OwnedString 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); |
| +} |