Index: compiled/filter/ElemHideBase.cpp |
=================================================================== |
--- a/compiled/filter/ElemHideBase.cpp |
+++ b/compiled/filter/ElemHideBase.cpp |
@@ -14,16 +14,17 @@ |
* 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" |
+#include "../Utils.h" |
ABP_NS_USING |
namespace |
{ |
void NormalizeWhitespace(DependentString& text, String::size_type& domainsEnd, |
String::size_type& selectorStart) |
{ |
@@ -46,29 +47,43 @@ |
delta++; |
else |
text[pos - delta] = text[pos]; |
} |
selectorStart -= delta; |
text.reset(text, 0, len - delta); |
} |
+ |
+ static constexpr String::value_type ELEM_HIDE_DELIMITER[] = u"##"; |
+ static constexpr String::size_type ELEM_HIDE_DELIMITER_LEN = str_length_of(ELEM_HIDE_DELIMITER); |
+ |
+ static constexpr String::value_type ELEM_HIDE_EMULATION_DELIMITER[] = u"#?#"; |
+ static constexpr String::size_type ELEM_HIDE_EMULATION_DELIMITER_LEN = str_length_of(ELEM_HIDE_EMULATION_DELIMITER); |
+ |
+ static constexpr String::value_type OLD_PROPS_SELECTOR[] = u"[-abp-properties="; |
+ static constexpr String::size_type OLD_PROPS_SELECTOR_LEN = str_length_of(OLD_PROPS_SELECTOR); |
+ |
+ static constexpr String::value_type PROPS_SELECTOR[] = u":-abp-properties("; |
+ static constexpr String::size_type PROPS_SELECTOR_LEN = str_length_of(PROPS_SELECTOR); |
} |
ElemHideBase::ElemHideBase(Type type, const String& text, const ElemHideData& data) |
: ActiveFilter(type, text, false), mData(data) |
{ |
if (mData.HasDomains()) |
ParseDomains(mData.GetDomainsSource(mText), u','); |
} |
-Filter::Type ElemHideBase::Parse(DependentString& text, ElemHideData& data) |
+Filter::Type ElemHideBase::Parse(DependentString& text, ElemHideData& data, bool& needConversion) |
{ |
StringScanner scanner(text); |
+ needConversion = false; |
sergei
2018/02/14 15:59:35
Perhaps, it should be the very first instruction o
hub
2018/02/14 17:05:20
Done.
|
+ |
// Domains part |
bool seenSpaces = false; |
while (!scanner.done()) |
{ |
String::value_type next = scanner.next(); |
if (next == u'#') |
{ |
data.mDomainsEnd = scanner.position(); |
@@ -86,19 +101,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 |
@@ -108,30 +126,156 @@ |
data.mSelectorStart = scanner.position() + 1; |
// 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(); |
+ // We still need to check the old syntax. It will be converted when |
+ // we instantiate the filter. |
+ if (!emulation && |
+ text.find(OLD_PROPS_SELECTOR, data.mSelectorStart, OLD_PROPS_SELECTOR_LEN) != text.npos) |
+ { |
+ needConversion = true; |
+ emulation = !exception; |
+ } |
+ |
if (exception) |
return Type::ELEMHIDEEXCEPTION; |
- if (text.find(u"[-abp-properties="_str, data.mSelectorStart) != text.npos) |
+ if (emulation) |
return Type::ELEMHIDEEMULATION; |
return Type::ELEMHIDE; |
} |
namespace |
{ |
+ struct Range |
+ { |
+ String::size_type start; |
+ String::size_type end; |
+ String::size_type len() const |
+ { |
+ return end - start; |
+ } |
+ String::size_type byte_len() const |
+ { |
+ return len() * sizeof(String::value_type); |
+ } |
+ }; |
+} |
+ |
+// Convert filter from the old syntax to the new. |
+DependentString ElemHideBase::ConvertFilter(String& text, String::size_type& at) |
+{ |
+ Range prefix = {at, text.find(OLD_PROPS_SELECTOR, at, OLD_PROPS_SELECTOR_LEN)}; |
+ if (prefix.end == text.npos) |
+ return DependentString(text); |
+ |
+ auto length = text.length(); |
+ Range suffix = {at, length}; |
+ Range properties = { prefix.end + OLD_PROPS_SELECTOR_LEN, 0 }; |
+ String::value_type quote = 0; |
+ for (auto index = properties.start; |
+ index < length && (suffix.start == at); index++) |
+ { |
+ auto c = text[index]; |
+ switch (c) |
+ { |
+ case u'"': |
+ case u'\'': |
+ if (quote == 0) |
+ { |
+ // syntax error: we already have a quoted section. |
+ if (properties.end) |
+ return DependentString(); |
+ |
+ quote = c; |
+ properties.start = index + 1; |
+ } |
+ else if (quote == c) |
+ { |
+ // end of quoted. |
+ quote = 0; |
+ properties.end = index; |
+ } |
+ break; |
+ case u']': |
sergei
2018/02/14 15:59:35
What about filter containing `[-abp-properties=wha
hub
2018/02/14 17:05:20
This would definitely be invalid. I'll make sure t
hub
2018/02/22 18:56:30
It is definitely handled in that last patch.
|
+ if (quote == 0) |
+ { |
+ if (properties.end == 0) |
+ return DependentString(); |
+ suffix.start = index + 1; |
+ } |
+ break; |
+ default: |
+ break; |
+ } |
+ } |
+ |
+ if (suffix.start == at) |
+ return DependentString(); |
+ |
+ String::size_type delimiter = text.find(ELEM_HIDE_DELIMITER, 0, |
+ ELEM_HIDE_DELIMITER_LEN); |
+ // +1 for the replacement of "##" by "#?#" |
+ if (delimiter != text.npos) |
+ at++; |
+ auto new_len = at + prefix.len() + PROPS_SELECTOR_LEN + properties.len() + 1 /* ) */ + suffix.len(); |
+ |
+ assert2(new_len + 1 == length || (delimiter == text.npos && new_len + 2 == length), u"Inconsistent length in filter conversion."_str); |
+ |
+ DependentString converted(text, 0, new_len); |
+ |
+ if (suffix.len()) |
+ { |
+ new_len -= suffix.len(); |
+ std::memmove(converted.data() + new_len, |
+ text.data() + suffix.start, |
+ suffix.byte_len()); |
+ } |
+ new_len--; |
+ // here we need to move the properties before inserting the ')' |
+ auto parens = new_len; |
+ if (properties.len()) |
+ { |
+ new_len -= properties.len(); |
+ std::memmove(converted.data() + new_len, |
+ text.data() + properties.start, properties.byte_len()); |
+ } |
+ converted[parens] = u')'; |
+ |
+ new_len -= PROPS_SELECTOR_LEN; |
+ std::memcpy(converted.data() + new_len, |
+ PROPS_SELECTOR, |
+ PROPS_SELECTOR_LEN * sizeof(String::value_type)); |
+ if (prefix.len()) |
+ { |
+ new_len -= prefix.len(); |
+ std::memmove(converted.data() + new_len, |
+ text.data() + prefix.start, prefix.byte_len()); |
+ } |
+ |
+ if (delimiter != String::npos) |
+ { |
+ std::memcpy(converted.data() + delimiter, ELEM_HIDE_EMULATION_DELIMITER, |
+ ELEM_HIDE_EMULATION_DELIMITER_LEN * sizeof(String::value_type)); |
+ } |
+ |
+ return converted; |
+} |
+ |
+namespace |
+{ |
static constexpr String::value_type OPENING_CURLY_REPLACEMENT[] = u"\\7B "; |
static constexpr String::value_type CLOSING_CURLY_REPLACEMENT[] = u"\\7D "; |
- static constexpr String::size_type CURLY_REPLACEMENT_SIZE = sizeof(OPENING_CURLY_REPLACEMENT) / sizeof(OPENING_CURLY_REPLACEMENT[0]) - 1; |
+ static constexpr String::size_type CURLY_REPLACEMENT_SIZE = str_length_of(OPENING_CURLY_REPLACEMENT); |
OwnedString EscapeCurlies(String::size_type replacementCount, |
const DependentString& str) |
{ |
OwnedString result(str.length() + replacementCount * (CURLY_REPLACEMENT_SIZE - 1)); |
String::value_type* current = result.data(); |
for (String::size_type i = 0; i < str.length(); i++) |