Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: compiled/filter/ElemHideBase.cpp

Issue 29595633: Issue 5870 - Implement the new ElemHideEmulation filter type (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Added missing ABP_NS macros Created Feb. 9, 2018, 8:34 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
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,26 +47,38 @@
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 = 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 = 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 = LENGTH_OF(OLD_PROPS_SELECTOR);
+
+ static constexpr String::value_type PROPS_SELECTOR[] = u":-abp-properties(";
+ static constexpr String::size_type PROPS_SELECTOR_LEN = 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);
// Domains part
bool seenSpaces = false;
while (!scanner.done())
{
String::value_type next = scanner.next();
@@ -86,19 +99,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 +124,157 @@
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)
+{
+ auto length = text.length();
+ Range prefix = {at, 0};
+ Range suffix = {at, length};
+ prefix.end = text.find(OLD_PROPS_SELECTOR, at, OLD_PROPS_SELECTOR_LEN);
sergei 2018/02/12 12:53:18 not important but perhaps it would be better to sa
hub 2018/02/12 18:14:39 Done.
+ if (prefix.end != text.npos)
sergei 2018/02/12 12:53:19 What about returning DependentString(text); here i
hub 2018/02/12 18:14:39 Done.
+ {
+ Range properties = { prefix.end + OLD_PROPS_SELECTOR_LEN, 0 };
+ String::value_type quote = 0;
+ bool closing = false;
+ for (auto index = properties.start;
+ index < length && !closing; 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']':
+ if (quote == 0)
+ {
+ if (properties.end == 0)
+ return DependentString();
+ suffix.start = index + 1;
+ closing = true;
sergei 2018/02/12 12:53:19 What about using of suffix.start instead of `closi
hub 2018/02/12 18:14:39 suffix.start is initialised to `at`. So I'll use t
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ 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++;
sergei 2018/02/12 12:53:20 BTW, if there is no such delimiter then is it a ma
hub 2018/02/12 18:14:40 no. #@# is valid too. We could check if it is #@#
+ auto new_len = prefix.len() + suffix.len() + properties.len()
+ + PROPS_SELECTOR_LEN + 1 + at;
sergei 2018/02/12 12:53:19 What about at + prefix.len() + PROPS_SELECTOR_LEN
hub 2018/02/12 18:14:39 Done.
+
sergei 2018/02/12 12:53:18 Could you please add the assert here that new_len
hub 2018/02/12 18:14:40 Done.
+ 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::memmove(converted.data() + new_len,
sergei 2018/02/12 12:53:18 logically it should be memcpy but since memmove do
hub 2018/02/12 18:14:39 You are right. Changing it to memcpy().
+ 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::memmove(converted.data() + delimiter, ELEM_HIDE_EMULATION_DELIMITER,
+ ELEM_HIDE_EMULATION_DELIMITER_LEN * sizeof(String::value_type));
+ }
+
+ return converted;
+ }
+
+ return DependentString(text);
+}
+
+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 = 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++)

Powered by Google App Engine
This is Rietveld