| LEFT | RIGHT | 
|    1 #include "ElemHideBase.h" |    1 #include "ElemHideBase.h" | 
|    2 #include "ElemHideFilter.h" |    2 #include "CSSPropertyFilter.h" | 
|    3 #include "ElemHideException.h" |  | 
|    4 #include "StringScanner.h" |    3 #include "StringScanner.h" | 
|    5  |    4  | 
|    6 ElemHideBase::ElemHideBase(const std::u16string& text, |    5 namespace | 
|    7     const std::u16string& domains, const std::u16string& selector) |  | 
|    8     : ActiveFilter(text, false), selector(selector) |  | 
|    9 { |    6 { | 
|   10   if (!domains.empty()) |    7   void NormalizeWhitespace(DependentString& text, String::size_type& domainsEnd, | 
|   11     ParseDomains(domains, u','); |    8       String::size_type& selectorStart) | 
 |    9   { | 
 |   10     // For element hiding filters we only want to remove spaces preceding the | 
 |   11     // selector part. The positions we've determined already have to be adjusted | 
 |   12     // accordingly. | 
 |   13  | 
 |   14     String::size_type delta = 0; | 
 |   15     String::size_type len = text.length(); | 
 |   16  | 
 |   17     // The first character is guaranteed to be a non-space, the string has been | 
 |   18     // trimmed earlier. | 
 |   19     for (String::size_type pos = 1; pos < len; pos++) | 
 |   20     { | 
 |   21       if (pos == domainsEnd) | 
 |   22         domainsEnd -= delta; | 
 |   23  | 
 |   24       // Only spaces before selectorStart position should be removed. | 
 |   25       if (pos < selectorStart && text[pos] == ' ') | 
 |   26         delta++; | 
 |   27       else | 
 |   28         text[pos - delta] = text[pos]; | 
 |   29     } | 
 |   30     selectorStart -= delta; | 
 |   31  | 
 |   32     text.reset(text, 0, len - delta); | 
 |   33   } | 
|   12 } |   34 } | 
|   13  |   35  | 
|   14 Filter::Type ElemHideBase::Parse(const std::u16string& text, size_t* domainsEnd, |   36 ElemHideBase::ElemHideBase(Type type, const String& text, const ElemHideBaseData
     & data) | 
|   15     size_t* selectorStart) |   37     : ActiveFilter(type, text, false), mData(data) | 
 |   38 { | 
 |   39   if (mData.HasDomains()) | 
 |   40     ParseDomains(mData.GetDomainsSource(mText), u','); | 
 |   41 } | 
 |   42  | 
 |   43 Filter::Type ElemHideBase::Parse(DependentString& text, ElemHideData& data) | 
|   16 { |   44 { | 
|   17   StringScanner scanner(text); |   45   StringScanner scanner(text); | 
|   18  |   46  | 
|   19   // Domains part |   47   // Domains part | 
|   20   loop: |   48   bool seenSpaces = false; | 
|   21   while (!scanner.done()) |   49   while (!scanner.done()) | 
|   22   { |   50   { | 
|   23     char16_t next = scanner.next(); |   51     String::value_type next = scanner.next(); | 
|   24     if (next == u'#') |   52     if (next == u'#') | 
|   25     { |   53     { | 
|   26       *domainsEnd = scanner.position(); |   54       data.mDomainsEnd = scanner.position(); | 
|   27       break; |   55       break; | 
|   28     } |   56     } | 
|   29  |   57  | 
|   30     switch (next) |   58     switch (next) | 
|   31     { |   59     { | 
|   32       case u'/': |   60       case u'/': | 
|   33       case u'*': |   61       case u'*': | 
|   34       case u'|': |   62       case u'|': | 
|   35       case u'@': |   63       case u'@': | 
|   36       case u'"': |   64       case u'"': | 
|   37       case u'!': |   65       case u'!': | 
|   38         return Type::UNKNOWN; |   66         return Type::UNKNOWN; | 
 |   67       case u' ': | 
 |   68         seenSpaces = true; | 
 |   69         break; | 
|   39     } |   70     } | 
|   40   } |   71   } | 
|   41  |   72  | 
|   42   bool exception = false; |   73   seenSpaces |= scanner.skip(u' '); | 
|   43   char16_t next = scanner.next(); |   74   bool exception = scanner.skipOne(u'@'); | 
|   44   if (next == u'@') |   75   if (exception) | 
|   45   { |   76     seenSpaces |= scanner.skip(u' '); | 
|   46     exception = true; |  | 
|   47     next = scanner.next(); |  | 
|   48   } |  | 
|   49  |   77  | 
 |   78   String::value_type next = scanner.next(); | 
|   50   if (next != u'#') |   79   if (next != u'#') | 
|   51     return Type::UNKNOWN; |   80     return Type::UNKNOWN; | 
|   52  |   81  | 
|   53   // Selector part |   82   // Selector part | 
|   54  |   83  | 
|   55   // Selector shouldn't be empty |   84   // Selector shouldn't be empty | 
 |   85   seenSpaces |= scanner.skip(u' '); | 
|   56   if (scanner.done()) |   86   if (scanner.done()) | 
|   57     return Type::UNKNOWN; |   87     return Type::UNKNOWN; | 
|   58  |   88  | 
|   59   *selectorStart = scanner.position() + 1; |   89   data.mSelectorStart = scanner.position() + 1; | 
|   60   while (!scanner.done()) |   90   while (!scanner.done()) | 
|   61   { |   91   { | 
|   62     switch (scanner.next()) |   92     switch (scanner.next()) | 
|   63     { |   93     { | 
|   64       case u'{': |   94       case u'{': | 
|   65       case u'}': |   95       case u'}': | 
|   66         return Type::UNKNOWN; |   96         return Type::UNKNOWN; | 
|   67     } |   97     } | 
|   68   } |   98   } | 
|   69  |   99  | 
|   70   return exception ? Type::ELEMHIDEEXCEPTION : Type::ELEMHIDE; |  100   // We are done validating, now we can normalize whitespace and the domain part | 
 |  101   if (seenSpaces) | 
 |  102     NormalizeWhitespace(text, data.mDomainsEnd, data.mSelectorStart); | 
 |  103   DependentString(text, 0, data.mDomainsEnd).toLower(); | 
 |  104  | 
 |  105   if (exception) | 
 |  106     return Type::ELEMHIDEEXCEPTION; | 
 |  107  | 
 |  108   do | 
 |  109   { | 
 |  110     // Is this a CSS property rule maybe? | 
 |  111     DependentString searchString(u"[-abp-properties="_str); | 
 |  112     data.mPrefixEnd = text.find(searchString, data.mSelectorStart); | 
 |  113     if (data.mPrefixEnd == text.npos || | 
 |  114         data.mPrefixEnd + searchString.length() + 1 >= text.length()) | 
 |  115     { | 
 |  116       break; | 
 |  117     } | 
 |  118  | 
 |  119     data.mRegexpStart = data.mPrefixEnd + searchString.length() + 1; | 
 |  120     char16_t quotation = text[data.mRegexpStart - 1]; | 
 |  121     if (quotation != u'\'' && quotation != u'"') | 
 |  122       break; | 
 |  123  | 
 |  124     data.mRegexpEnd = text.find(quotation, data.mRegexpStart); | 
 |  125     if (data.mRegexpEnd == text.npos || data.mRegexpEnd + 1 >= text.length() || | 
 |  126       text[data.mRegexpEnd + 1] != u']') | 
 |  127     { | 
 |  128       break; | 
 |  129     } | 
 |  130  | 
 |  131     data.mSuffixStart = data.mRegexpEnd + 2; | 
 |  132     return Type::CSSPROPERTY; | 
 |  133   } while (false); | 
 |  134  | 
 |  135   return Type::ELEMHIDE; | 
|   71 } |  136 } | 
|   72  |  137  | 
|   73 ElemHideBase* ElemHideBase::Create(const std::u16string& text) |  138 OwnedString ElemHideBase::GetSelectorDomain() const | 
|   74 { |  139 { | 
|   75   size_t domainsEnd; |  140   /* TODO this is inefficient */ | 
|   76   size_t selectorStart; |  141   OwnedString result; | 
|   77   Type type = Parse(text, &domainsEnd, &selectorStart); |  142   if (mDomains) | 
|   78   if (type == Type::UNKNOWN) |  | 
|   79     return nullptr; |  | 
|   80  |  | 
|   81   std::u16string domains(text.substr(0, domainsEnd)); |  | 
|   82   std::u16string selector(text.substr(selectorStart)); |  | 
|   83   if (type == Type::ELEMHIDEEXCEPTION) |  | 
|   84     return new ElemHideException(text, domains, selector); |  | 
|   85   else |  | 
|   86     return new ElemHideFilter(text, domains, selector); |  | 
|   87 } |  | 
|   88  |  | 
|   89 const std::u16string ElemHideBase::GetSelectorDomain() const |  | 
|   90 { |  | 
|   91   std::u16string result; |  | 
|   92   for (auto it = domains.begin(); it != domains.end(); ++it) |  | 
|   93   { |  143   { | 
|   94     if (it->second && !it->first.empty()) |  144     for (auto it = mDomains->begin(); it != mDomains->end(); ++it) | 
|   95     { |  145     { | 
|   96       if (!result.empty()) |  146       if (it->second && !it->first.empty()) | 
|   97         result.append(u","); |  147       { | 
|   98       result.append(it->first); |  148         if (!result.empty()) | 
 |  149           result.append(u','); | 
 |  150         result.append(it->first); | 
 |  151       } | 
|   99     } |  152     } | 
|  100   } |  153   } | 
|  101   return result; |  154   return result; | 
|  102 } |  155 } | 
| LEFT | RIGHT |