Index: compiled/filter/ElemHideBase.cpp |
=================================================================== |
--- a/compiled/filter/ElemHideBase.cpp |
+++ b/compiled/filter/ElemHideBase.cpp |
@@ -10,16 +10,18 @@ |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
*/ |
+#include <cstring> |
+ |
#include "ElemHideBase.h" |
#include "../StringScanner.h" |
namespace |
{ |
void NormalizeWhitespace(DependentString& text, String::size_type& domainsEnd, |
String::size_type& selectorStart) |
{ |
@@ -42,20 +44,112 @@ |
delta++; |
else |
text[pos - delta] = text[pos]; |
} |
selectorStart -= delta; |
text.reset(text, 0, len - delta); |
} |
+ |
+ // Convert filter from the old syntax to the new. |
+ OwnedString ConvertFilter(const String& text, String::size_type at) |
+ { |
+ static const auto propsSelector = u"[-abp-properties="_str; |
+ static const auto newPropsSelector = u":-abp-properties("_str; |
+ auto selectorPos = text.find(propsSelector, at); |
+ if (selectorPos != text.npos) |
+ { |
+ auto length = text.length(); |
+ auto properties = selectorPos + propsSelector.length(); |
+ String::value_type quote = 0; |
+ bool escape = false; |
+ String::size_type removed = 0; // how many chars we remove |
+ String::size_type end = properties; |
+ String::size_type quote_start = 0; |
+ String::size_type quote_end = 0; |
+ for (auto index = properties; |
+ index < length && end == properties; index++) |
+ { |
+ if (escape) |
+ { |
+ escape = false; |
+ continue; |
+ } |
+ |
+ auto c = text[index]; |
+ switch (c) |
+ { |
+ case '\\': |
+ escape = true; |
+ break; |
+ case '"': |
+ case '\'': |
+ if (quote == 0) |
+ { |
+ quote = c; |
+ quote_start = index + 1; |
+ } |
+ else if (quote == c) |
+ { |
+ // end of quoted. |
+ quote = 0; |
+ removed += 2; |
+ quote_end = index; |
+ } |
+ break; |
+ case ']': |
+ if (quote == 0) |
+ end = index + 1; // end of properties (after ]) |
+ break; |
+ default: |
+ break; |
+ } |
+ } |
+ |
+ if (quote != 0) |
+ quote_end = end - 1; |
+ else if (quote_end <= quote_start) |
+ { |
+ // we likely didn't find a quoted content so we just take it as is. |
+ quote_start = properties; |
+ quote_end = end - 1; |
+ } |
+ |
+ OwnedString converted(length - removed); |
+ String::size_type offset = 0; |
+ std::memcpy(converted.data(), text.data(), |
+ selectorPos * sizeof(String::value_type)); |
+ offset += selectorPos; |
+ |
+ std::memcpy(converted.data() + offset, newPropsSelector.data(), |
+ newPropsSelector.length() * sizeof(String::value_type)); |
+ offset += newPropsSelector.length(); |
+ |
+ std::memcpy(converted.data() + offset, text.data() + quote_start, |
+ (quote_end - quote_start) * sizeof(String::value_type)); |
+ offset += quote_end - quote_start; |
+ |
+ std::memcpy(converted.data() + offset, u")", sizeof(String::value_type)); |
+ offset++; |
+ |
+ std::memcpy(converted.data() + offset, text.data() + end, |
+ (length - end) * sizeof(String::value_type)); |
+ offset += (length - end) * sizeof(String::value_type); |
+ |
+ return converted; |
+ } |
+ |
+ return OwnedString(text); |
+ } |
} |
ElemHideBase::ElemHideBase(Type type, const String& text, const ElemHideData& data) |
- : ActiveFilter(type, text, false), mData(data) |
+ : ActiveFilter(type, ConvertFilter(text, data.mSelectorStart), false), |
+ mData(data) |
{ |
if (mData.HasDomains()) |
ParseDomains(mData.GetDomainsSource(mText), u','); |
} |
Filter::Type ElemHideBase::Parse(DependentString& text, ElemHideData& data) |
{ |
StringScanner scanner(text); |
@@ -82,19 +176,22 @@ |
return Type::UNKNOWN; |
case u' ': |
seenSpaces = true; |
break; |
} |
} |
seenSpaces |= scanner.skip(u' '); |
+ bool emulation = false; |
bool exception = scanner.skipOne(u'@'); |
if (exception) |
seenSpaces |= scanner.skip(u' '); |
+ else |
+ emulation = scanner.skipOne(u'?'); |
String::value_type next = scanner.next(); |
if (next != u'#') |
return Type::UNKNOWN; |
// Selector part |
// Selector shouldn't be empty |
@@ -116,17 +213,17 @@ |
// We are done validating, now we can normalize whitespace and the domain part |
if (seenSpaces) |
NormalizeWhitespace(text, data.mDomainsEnd, data.mSelectorStart); |
DependentString(text, 0, data.mDomainsEnd).toLower(); |
if (exception) |
return Type::ELEMHIDEEXCEPTION; |
- if (text.find(u"[-abp-properties="_str, data.mSelectorStart) != text.npos) |
+ if (emulation) |
return Type::ELEMHIDEEMULATION; |
return Type::ELEMHIDE; |
} |
OwnedString ElemHideBase::GetSelectorDomain() const |
{ |
/* TODO this is inefficient */ |