| LEFT | RIGHT | 
|    1 /* |    1 /* | 
|    2  * This file is part of Adblock Plus <https://adblockplus.org/>, |    2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
|    3  * Copyright (C) 2006-present eyeo GmbH |    3  * Copyright (C) 2006-present eyeo GmbH | 
|    4  * |    4  * | 
|    5  * Adblock Plus is free software: you can redistribute it and/or modify |    5  * Adblock Plus is free software: you can redistribute it and/or modify | 
|    6  * it under the terms of the GNU General Public License version 3 as |    6  * it under the terms of the GNU General Public License version 3 as | 
|    7  * published by the Free Software Foundation. |    7  * published by the Free Software Foundation. | 
|    8  * |    8  * | 
|    9  * Adblock Plus is distributed in the hope that it will be useful, |    9  * Adblock Plus is distributed in the hope that it will be useful, | 
|   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of |   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|   12  * GNU General Public License for more details. |   12  * GNU General Public License for more details. | 
|   13  * |   13  * | 
|   14  * You should have received a copy of the GNU General Public License |   14  * You should have received a copy of the GNU General Public License | 
|   15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. |   15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
|   16  */ |   16  */ | 
|   17  |   17  | 
|   18 #include "ElemHide.h" |   18 #include "ElemHide.h" | 
|   19  |   19  | 
|   20 DependentString _ElemHide_SelectorList::SelectorAt(size_t idx) const |   20 OwnedString ElemHide_SelectorList::SelectorAt(size_t idx) const | 
|   21 { |   21 { | 
|   22   return DependentString(mSelectors[idx]->GetSelector()); |   22   return mSelectors[idx]->GetSelector(); | 
|   23 } |   23 } | 
|   24  |   24  | 
|   25 const String& _ElemHide_SelectorList::FilterKeyAt(size_t idx) const |   25 const String& ElemHide_SelectorList::FilterKeyAt(size_t idx) const | 
|   26 { |   26 { | 
|   27   return mSelectors[idx]->GetText(); |   27   return mSelectors[idx]->GetText(); | 
|   28 } |   28 } | 
|   29  |  | 
|   30 ElemHide* ElemHide::mInstance = new ElemHide(); |  | 
|   31  |   29  | 
|   32 void ElemHide::Clear() |   30 void ElemHide::Clear() | 
|   33 { |   31 { | 
|   34   mFilters.clear(); |   32   mFilters.clear(); | 
|   35   mExceptions.clear(); |   33   mExceptions.clear(); | 
|   36   mFiltersByDomain.clear(); |   34   mFiltersByDomain.clear(); | 
|   37   mKnownExceptions.clear(); |   35   mKnownExceptions.clear(); | 
|   38 } |   36 } | 
|   39  |   37  | 
|   40 namespace { |   38 namespace | 
|   41  |   39 { | 
|   42   ActiveFilter::DomainMap* DefaultDomains() |   40   const ActiveFilter::DomainMap defaultDomains = | 
|   43   { |   41   { | 
|   44     static ActiveFilter::DomainMap defaultDomains; |   42     { ActiveFilter::DEFAULT_DOMAIN, true } | 
|   45     if (defaultDomains.empty()) |   43   }; | 
|   46       defaultDomains[u""_str] = true; |   44 } | 
|   47     return &defaultDomains; |   45  | 
|   48   } |   46 void ElemHide::AddToFiltersByDomain(const ElemHideBasePtr& filter) | 
|   49  |   47 { | 
|   50 } |   48   const auto* domains = filter->GetDomains(); | 
|   51  |  | 
|   52 void ElemHide::AddToFiltersByDomain(ElemHideBase& filter) |  | 
|   53 { |  | 
|   54   auto domains = filter.GetDomains(); |  | 
|   55   if (!domains) |   49   if (!domains) | 
|   56     domains = DefaultDomains(); |   50     domains = &defaultDomains; | 
|   57  |   51  | 
|   58   DependentString text(filter.GetText()); |   52   DependentString text(filter->GetText()); | 
|   59   for (auto& domain : *domains) |   53   for (const auto& domain : *domains) | 
|   60   { |   54   { | 
|   61     auto& filters = mFiltersByDomain[domain.first]; |   55     auto& filters = mFiltersByDomain[domain.first]; | 
|   62     if (domain.second) |   56     if (domain.second) | 
|   63       filters[text] = ElemHideBasePtr(&filter); |   57       filters[text] = filter; | 
|   64     else |   58     else | 
|   65     { |   59       filters[text] = ElemHideBasePtr(); | 
|   66       auto iter = filters.find(text); |  | 
|   67       if (iter != filters.end()) |  | 
|   68         filters.erase(iter); |  | 
|   69     } |  | 
|   70   } |   60   } | 
|   71 } |   61 } | 
|   72  |   62  | 
|   73 void ElemHide::Add(ElemHideBase& filter) |   63 void ElemHide::Add(ElemHideBase& filter) | 
|   74 { |   64 { | 
|   75   // we must ensure we have the right class. |   65   // we must ensure we have the right class. | 
|   76   // This is an error, but we might get Invalid filters. |   66   // This is an error, but we might get Invalid filters. | 
|   77   if (!filter.As<ElemHideBase>()) |   67   if (!filter.As<ElemHideBase>()) | 
|   78     return; |   68     return; | 
|   79  |   69  | 
|   80   DependentString text(filter.GetText()); |   70   DependentString text(filter.GetText()); | 
|   81   if (filter.mType == Filter::Type::ELEMHIDEEXCEPTION) |   71   if (filter.mType == Filter::Type::ELEMHIDEEXCEPTION) | 
|   82   { |   72   { | 
|   83     if (mKnownExceptions.find(text)) |   73     if (mKnownExceptions.find(text)) | 
|   84       return; |   74       return; | 
|   85  |   75  | 
|   86     auto selector = filter.GetSelector(); |   76     auto selector = filter.GetSelector(); | 
|   87     mExceptions[selector].push_back( |   77     mExceptions[selector].emplace_back(filter.As<ElemHideException>()); | 
|   88       ElemHideExceptionPtr(filter.As<ElemHideException>())); |   78  | 
|   89  |   79     // Selector is no longer unconditional | 
|   90     // Selector is not longer unconditional |   80     auto entry = mUnconditionalSelectors.find(selector); | 
|   91     mUnconditionalSelectors.erase(text); |   81     if (entry && entry->second) | 
|   92  |   82     { | 
 |   83       AddToFiltersByDomain(entry->second); | 
 |   84       mUnconditionalSelectors.erase(selector); | 
 |   85       mUnconditionalSelectorsCache.reset(); | 
 |   86     } | 
|   93     mKnownExceptions.insert(text); |   87     mKnownExceptions.insert(text); | 
|   94   } |   88   } | 
|   95   else |   89   else | 
|   96   { |   90   { | 
|   97     if (mFilters.find(text)) |   91     if (mFilters.find(text)) | 
|   98       return; |   92       return; | 
|   99  |   93  | 
|  100     mFilters[text] = ElemHideBasePtr(filter.As<ElemHideBase>()); |   94     auto selector = filter.GetSelector(); | 
 |   95     mFilters[text] = &filter; | 
|  101     if (!((filter.GetDomains() && filter.GetDomains()->size()) || |   96     if (!((filter.GetDomains() && filter.GetDomains()->size()) || | 
|  102           mExceptions.find(filter.GetSelector()))) |   97           mExceptions.find(selector))) | 
|  103     { |   98     { | 
|  104       // The new filter's selector is unconditionally applied to all domains |   99       // The new filter's selector is unconditionally applied to all domains | 
|  105       mUnconditionalSelectors.insert(text); |  100       mUnconditionalSelectors[selector] = ElemHideBasePtr(&filter); | 
 |  101       mUnconditionalSelectorsCache.reset(); | 
|  106     } |  102     } | 
|  107     else |  103     else | 
|  108     { |  104       AddToFiltersByDomain(ElemHideBasePtr(&filter)); | 
|  109       AddToFiltersByDomain(filter); |  | 
|  110     } |  | 
|  111   } |  105   } | 
|  112 } |  106 } | 
|  113  |  107  | 
|  114 void ElemHide::Remove(ElemHideBase& filter) |  108 void ElemHide::Remove(ElemHideBase& filter) | 
|  115 { |  109 { | 
|  116   DependentString text(filter.GetText()); |  110   DependentString text(filter.GetText()); | 
|  117  |  111  | 
|  118   if (filter.mType == Filter::Type::ELEMHIDEEXCEPTION) |  112   auto selector = filter.GetSelector(); | 
 |  113   auto exceptionFilter = filter.As<ElemHideException>(); | 
 |  114   if (exceptionFilter) | 
|  119   { |  115   { | 
|  120     // never seen the exception. |  116     // never seen the exception. | 
|  121     if (!mKnownExceptions.find(text)) |  117     if (!mKnownExceptions.find(text)) | 
|  122       return; |  118       return; | 
|  123  |  119  | 
|  124     auto selector = filter.GetSelector(); |  | 
|  125     auto& list = mExceptions[selector]; |  120     auto& list = mExceptions[selector]; | 
|  126     auto iter = std::find( |  121     auto iter = std::find(list.begin(), list.end(), | 
|  127       list.begin(), list.end(), |  122                           ElemHideExceptionPtr(exceptionFilter)); | 
|  128       ElemHideExceptionPtr(filter.As<ElemHideException>())); |  | 
|  129     if (iter != list.end()) |  123     if (iter != list.end()) | 
|  130       list.erase(iter); |  124       list.erase(iter); | 
|  131     mKnownExceptions.erase(text); |  125     mKnownExceptions.erase(text); | 
|  132   } |  126   } | 
|  133   else |  127   else | 
|  134   { |  128   { | 
|  135     if (!mFilters.find(text)) |  129     if (!mFilters.find(text)) | 
|  136       return; |  130       return; | 
|  137  |  131  | 
|  138     if (mUnconditionalSelectors.find(text)) |  132     if (mUnconditionalSelectors.find(selector)) | 
|  139       mUnconditionalSelectors.erase(text); |  133     { | 
 |  134       mUnconditionalSelectors.erase(selector); | 
 |  135       mUnconditionalSelectorsCache.reset(); | 
 |  136     } | 
|  140     else |  137     else | 
|  141     { |  138     { | 
|  142       auto domains = filter.GetDomains(); |  139       const auto* domains = filter.GetDomains(); | 
|  143       for (auto domain : *domains) |  140       if (!domains) | 
 |  141         domains = &defaultDomains; | 
 |  142  | 
 |  143       for (const auto& domain : *domains) | 
|  144       { |  144       { | 
|  145         auto list = mFiltersByDomain[domain.first]; |  145         auto& list = mFiltersByDomain[domain.first]; | 
|  146         list.erase(text); |  146         list.erase(text); | 
|  147       } |  147       } | 
|  148     } |  148     } | 
|  149  |  149  | 
|  150     mFilters.erase(text); |  150     mFilters.erase(text); | 
|  151   } |  151   } | 
|  152 } |  152 } | 
|  153  |  153  | 
|  154 ElemHideException* ElemHide::GetException(const ElemHideBase& filter, |  154 ElemHideException* ElemHide::GetException(const ElemHideBase& filter, | 
|  155                                           DependentString& docDomain) const |  155                                           DependentString& docDomain) const | 
|  156 { |  156 { | 
|  157   auto exception = mExceptions.find(filter.GetSelector()); |  157   auto exception = mExceptions.find(filter.GetSelector()); | 
|  158   if (!exception) |  158   if (!exception) | 
|  159     return nullptr; |  159     return nullptr; | 
|  160  |  160  | 
|  161   auto& list = exception->second; |  161   auto& list = exception->second; | 
|  162   for (auto iter = list.rbegin(); iter != list.rend(); iter++) |  162   for (auto iter = list.rbegin(); iter != list.rend(); iter++) | 
|  163     if ((*iter)->IsActiveOnDomain(docDomain, u""_str)) |  163   { | 
 |  164     DependentString domain(docDomain); | 
 |  165     if (*iter && (*iter)->IsActiveOnDomain(domain)) | 
|  164     { |  166     { | 
|  165       ElemHideExceptionPtr filter(*iter); |  167       ElemHideExceptionPtr filter(*iter); | 
|  166       return filter.release(); |  168       return filter.release(); | 
|  167     } |  169     } | 
 |  170   } | 
|  168  |  171  | 
|  169   return nullptr; |  172   return nullptr; | 
|  170 } |  173 } | 
|  171  |  174  | 
|  172 _ElemHide_SelectorList* ElemHide::GetUnconditionalSelectors() const |  175 ElemHide_SelectorList* ElemHide::GetUnconditionalSelectors() const | 
|  173 { |  176 { | 
|  174   auto list = new _ElemHide_SelectorList; |  177   if (!mUnconditionalSelectorsCache) | 
|  175   annotate_address(list, "_ElemHide_SelectorList"); |  178   { | 
|  176   for (auto unconditional : mUnconditionalSelectors) |  179     mUnconditionalSelectorsCache = | 
|  177   { |  180       intrusive_ptr<ElemHide_SelectorList>(new ElemHide_SelectorList(), false); | 
|  178     auto filter = mFilters.find(unconditional.first); |  181     annotate_address(mUnconditionalSelectorsCache.get(), "ElemHide_SelectorList"
     ); | 
|  179     if (filter) |  182     for (const auto& unconditional : mUnconditionalSelectors) | 
|  180       list->push_back(filter->second); |  183     { | 
|  181   } |  184       if (!(unconditional.is_deleted() || unconditional.is_invalid())) | 
|  182   return list; |  185       { | 
|  183 } |  186         auto entry = mFilters.find(unconditional.second->GetText()); | 
|  184  |  187         if (entry) | 
|  185 _ElemHide_SelectorList* ElemHide::GetSelectorsForDomain(const String& domain, |  188           mUnconditionalSelectorsCache->push_back(entry->second); | 
 |  189       } | 
 |  190     } | 
 |  191   } | 
 |  192   return intrusive_ptr<ElemHide_SelectorList>(mUnconditionalSelectorsCache).rele
     ase(); | 
 |  193 } | 
 |  194  | 
 |  195 ElemHide_SelectorList* ElemHide::GetSelectorsForDomain(const String& domain, | 
|  186   Criteria criteria) const |  196   Criteria criteria) const | 
|  187 { |  197 { | 
|  188   _ElemHide_SelectorList* selectors; |  198   intrusive_ptr<ElemHide_SelectorList> selectors(new ElemHide_SelectorList()); | 
 |  199   annotate_address(selectors.get(), "ElemHide_SelectorList"); | 
|  189  |  200  | 
|  190   if (criteria < NO_UNCONDITIONAL) |  201   if (criteria < NO_UNCONDITIONAL) | 
|  191     selectors = GetUnconditionalSelectors(); |  202   { | 
|  192   else |  203     intrusive_ptr<ElemHide_SelectorList> selector(GetUnconditionalSelectors()); | 
|  193   { |  204     selectors->append(*selector); | 
|  194     selectors = new _ElemHide_SelectorList; |  205   } | 
|  195     annotate_address(selectors, "_ElemHide_SelectorList"); |  206  | 
|  196   } |  207   bool specificOnly = criteria >= SPECIFIC_ONLY; | 
|  197  |  | 
|  198   bool specificOnly = (criteria >= SPECIFIC_ONLY); |  | 
|  199   StringSet seenFilters; |  208   StringSet seenFilters; | 
|  200   DependentString docDomain(domain); |  209   DependentString docDomain(domain); | 
|  201  |  210  | 
|  202   DependentString currentDomain(domain); |  211   DependentString currentDomain(domain); | 
|  203   while (true) |  212   while (true) | 
|  204   { |  213   { | 
|  205     if (specificOnly && currentDomain.empty()) |  214     if (specificOnly && currentDomain.empty()) | 
|  206       break; |  215       break; | 
|  207  |  216  | 
|  208     auto filters = mFiltersByDomain.find(currentDomain); |  217     auto filters = mFiltersByDomain.find(currentDomain); | 
|  209     if (filters) |  218     if (filters) | 
|  210     { |  219     { | 
|  211       for (auto& entry : filters->second) |  220       for (const auto& entry : filters->second) | 
|  212       { |  221       { | 
|  213         if (entry.first.is_invalid()) |  222         if (entry.first.is_invalid() || entry.first.is_deleted()) | 
|  214           continue; |  223           continue; | 
|  215  |  224  | 
|  216         if (seenFilters.find(entry.first)) |  225         if (seenFilters.find(entry.first)) | 
|  217           continue; |  226           continue; | 
|  218         seenFilters.insert(entry.first); |  227         seenFilters.insert(entry.first); | 
|  219  |  228  | 
|  220         auto filter = entry.second; |  229         auto filter = entry.second; | 
|  221         if (filter && !GetException(*filter, docDomain)) |  230         if (filter && !GetException(*filter, docDomain)) | 
|  222           selectors->push_back(filter); |  231           selectors->push_back(filter); | 
|  223       } |  232       } | 
|  224     } |  233     } | 
|  225  |  234  | 
|  226     if (currentDomain.empty()) |  235     if (currentDomain.empty()) | 
|  227       break; |  236       break; | 
|  228  |  237  | 
|  229     auto nextDot = currentDomain.find('.'); |  238     auto nextDot = currentDomain.find(u'.'); | 
|  230     currentDomain = nextDot == String::npos ? |  239     currentDomain = nextDot == String::npos ? | 
|  231       u""_str : DependentString(currentDomain, nextDot + 1); |  240       u""_str : DependentString(currentDomain, nextDot + 1); | 
|  232   } |  241   } | 
|  233  |  242  | 
|  234   return selectors; |  243   return selectors.release(); | 
|  235 } |  244 } | 
| LEFT | RIGHT |