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

Side by Side 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: Last comment addressed. Created Feb. 13, 2018, 4:22 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « compiled/filter/ElemHideBase.h ('k') | compiled/filter/Filter.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <cstring> 18 #include <cstring>
19 19
20 #include "ElemHideBase.h" 20 #include "ElemHideBase.h"
21 #include "../StringScanner.h" 21 #include "../StringScanner.h"
22 #include "../Utils.h"
22 23
23 ABP_NS_USING 24 ABP_NS_USING
24 25
25 namespace 26 namespace
26 { 27 {
27 void NormalizeWhitespace(DependentString& text, String::size_type& domainsEnd, 28 void NormalizeWhitespace(DependentString& text, String::size_type& domainsEnd,
28 String::size_type& selectorStart) 29 String::size_type& selectorStart)
29 { 30 {
30 // For element hiding filters we only want to remove spaces preceding the 31 // For element hiding filters we only want to remove spaces preceding the
31 // selector part. The positions we've determined already have to be adjusted 32 // selector part. The positions we've determined already have to be adjusted
(...skipping 12 matching lines...) Expand all
44 // Only spaces before selectorStart position should be removed. 45 // Only spaces before selectorStart position should be removed.
45 if (pos < selectorStart && text[pos] == ' ') 46 if (pos < selectorStart && text[pos] == ' ')
46 delta++; 47 delta++;
47 else 48 else
48 text[pos - delta] = text[pos]; 49 text[pos - delta] = text[pos];
49 } 50 }
50 selectorStart -= delta; 51 selectorStart -= delta;
51 52
52 text.reset(text, 0, len - delta); 53 text.reset(text, 0, len - delta);
53 } 54 }
55
56 static constexpr String::value_type ELEM_HIDE_DELIMITER[] = u"##";
57 static constexpr String::size_type ELEM_HIDE_DELIMITER_LEN = str_length_of(ELE M_HIDE_DELIMITER);
58
59 static constexpr String::value_type ELEM_HIDE_EMULATION_DELIMITER[] = u"#?#";
60 static constexpr String::size_type ELEM_HIDE_EMULATION_DELIMITER_LEN = str_len gth_of(ELEM_HIDE_EMULATION_DELIMITER);
61
62 static constexpr String::value_type OLD_PROPS_SELECTOR[] = u"[-abp-properties= ";
63 static constexpr String::size_type OLD_PROPS_SELECTOR_LEN = str_length_of(OLD_ PROPS_SELECTOR);
64
65 static constexpr String::value_type PROPS_SELECTOR[] = u":-abp-properties(";
66 static constexpr String::size_type PROPS_SELECTOR_LEN = str_length_of(PROPS_SE LECTOR);
54 } 67 }
55 68
56 ElemHideBase::ElemHideBase(Type type, const String& text, const ElemHideData& da ta) 69 ElemHideBase::ElemHideBase(Type type, const String& text, const ElemHideData& da ta)
57 : ActiveFilter(type, text, false), mData(data) 70 : ActiveFilter(type, text, false), mData(data)
58 { 71 {
59 if (mData.HasDomains()) 72 if (mData.HasDomains())
60 ParseDomains(mData.GetDomainsSource(mText), u','); 73 ParseDomains(mData.GetDomainsSource(mText), u',');
61 } 74 }
62 75
63 Filter::Type ElemHideBase::Parse(DependentString& text, ElemHideData& data) 76 Filter::Type ElemHideBase::Parse(DependentString& text, ElemHideData& data, bool & needConversion)
64 { 77 {
65 StringScanner scanner(text); 78 StringScanner scanner(text);
66 79
80 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.
81
67 // Domains part 82 // Domains part
68 bool seenSpaces = false; 83 bool seenSpaces = false;
69 while (!scanner.done()) 84 while (!scanner.done())
70 { 85 {
71 String::value_type next = scanner.next(); 86 String::value_type next = scanner.next();
72 if (next == u'#') 87 if (next == u'#')
73 { 88 {
74 data.mDomainsEnd = scanner.position(); 89 data.mDomainsEnd = scanner.position();
75 break; 90 break;
76 } 91 }
77 92
78 switch (next) 93 switch (next)
79 { 94 {
80 case u'/': 95 case u'/':
81 case u'*': 96 case u'*':
82 case u'|': 97 case u'|':
83 case u'@': 98 case u'@':
84 case u'"': 99 case u'"':
85 case u'!': 100 case u'!':
86 return Type::UNKNOWN; 101 return Type::UNKNOWN;
87 case u' ': 102 case u' ':
88 seenSpaces = true; 103 seenSpaces = true;
89 break; 104 break;
90 } 105 }
91 } 106 }
92 107
93 seenSpaces |= scanner.skip(u' '); 108 seenSpaces |= scanner.skip(u' ');
109 bool emulation = false;
94 bool exception = scanner.skipOne(u'@'); 110 bool exception = scanner.skipOne(u'@');
95 if (exception) 111 if (exception)
96 seenSpaces |= scanner.skip(u' '); 112 seenSpaces |= scanner.skip(u' ');
113 else
114 emulation = scanner.skipOne(u'?');
97 115
98 String::value_type next = scanner.next(); 116 String::value_type next = scanner.next();
99 if (next != u'#') 117 if (next != u'#')
100 return Type::UNKNOWN; 118 return Type::UNKNOWN;
101 119
102 // Selector part 120 // Selector part
103 121
104 // Selector shouldn't be empty 122 // Selector shouldn't be empty
105 seenSpaces |= scanner.skip(u' '); 123 seenSpaces |= scanner.skip(u' ');
106 if (scanner.done()) 124 if (scanner.done())
107 return Type::UNKNOWN; 125 return Type::UNKNOWN;
108 126
109 data.mSelectorStart = scanner.position() + 1; 127 data.mSelectorStart = scanner.position() + 1;
110 128
111 // We are done validating, now we can normalize whitespace and the domain part 129 // We are done validating, now we can normalize whitespace and the domain part
112 if (seenSpaces) 130 if (seenSpaces)
113 NormalizeWhitespace(text, data.mDomainsEnd, data.mSelectorStart); 131 NormalizeWhitespace(text, data.mDomainsEnd, data.mSelectorStart);
114 DependentString(text, 0, data.mDomainsEnd).toLower(); 132 DependentString(text, 0, data.mDomainsEnd).toLower();
115 133
134 // We still need to check the old syntax. It will be converted when
135 // we instantiate the filter.
136 if (!emulation &&
137 text.find(OLD_PROPS_SELECTOR, data.mSelectorStart, OLD_PROPS_SELECTOR_LEN) != text.npos)
138 {
139 needConversion = true;
140 emulation = !exception;
141 }
142
116 if (exception) 143 if (exception)
117 return Type::ELEMHIDEEXCEPTION; 144 return Type::ELEMHIDEEXCEPTION;
118 145
119 if (text.find(u"[-abp-properties="_str, data.mSelectorStart) != text.npos) 146 if (emulation)
120 return Type::ELEMHIDEEMULATION; 147 return Type::ELEMHIDEEMULATION;
121 148
122 return Type::ELEMHIDE; 149 return Type::ELEMHIDE;
123 } 150 }
124 151
125 namespace 152 namespace
126 { 153 {
154 struct Range
155 {
156 String::size_type start;
157 String::size_type end;
158 String::size_type len() const
159 {
160 return end - start;
161 }
162 String::size_type byte_len() const
163 {
164 return len() * sizeof(String::value_type);
165 }
166 };
167 }
168
169 // Convert filter from the old syntax to the new.
170 DependentString ElemHideBase::ConvertFilter(String& text, String::size_type& at)
171 {
172 Range prefix = {at, text.find(OLD_PROPS_SELECTOR, at, OLD_PROPS_SELECTOR_LEN)} ;
173 if (prefix.end == text.npos)
174 return DependentString(text);
175
176 auto length = text.length();
177 Range suffix = {at, length};
178 Range properties = { prefix.end + OLD_PROPS_SELECTOR_LEN, 0 };
179 String::value_type quote = 0;
180 for (auto index = properties.start;
181 index < length && (suffix.start == at); index++)
182 {
183 auto c = text[index];
184 switch (c)
185 {
186 case u'"':
187 case u'\'':
188 if (quote == 0)
189 {
190 // syntax error: we already have a quoted section.
191 if (properties.end)
192 return DependentString();
193
194 quote = c;
195 properties.start = index + 1;
196 }
197 else if (quote == c)
198 {
199 // end of quoted.
200 quote = 0;
201 properties.end = index;
202 }
203 break;
204 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.
205 if (quote == 0)
206 {
207 if (properties.end == 0)
208 return DependentString();
209 suffix.start = index + 1;
210 }
211 break;
212 default:
213 break;
214 }
215 }
216
217 if (suffix.start == at)
218 return DependentString();
219
220 String::size_type delimiter = text.find(ELEM_HIDE_DELIMITER, 0,
221 ELEM_HIDE_DELIMITER_LEN);
222 // +1 for the replacement of "##" by "#?#"
223 if (delimiter != text.npos)
224 at++;
225 auto new_len = at + prefix.len() + PROPS_SELECTOR_LEN + properties.len() + 1 / * ) */ + suffix.len();
226
227 assert2(new_len + 1 == length || (delimiter == text.npos && new_len + 2 == len gth), u"Inconsistent length in filter conversion."_str);
228
229 DependentString converted(text, 0, new_len);
230
231 if (suffix.len())
232 {
233 new_len -= suffix.len();
234 std::memmove(converted.data() + new_len,
235 text.data() + suffix.start,
236 suffix.byte_len());
237 }
238 new_len--;
239 // here we need to move the properties before inserting the ')'
240 auto parens = new_len;
241 if (properties.len())
242 {
243 new_len -= properties.len();
244 std::memmove(converted.data() + new_len,
245 text.data() + properties.start, properties.byte_len());
246 }
247 converted[parens] = u')';
248
249 new_len -= PROPS_SELECTOR_LEN;
250 std::memcpy(converted.data() + new_len,
251 PROPS_SELECTOR,
252 PROPS_SELECTOR_LEN * sizeof(String::value_type));
253 if (prefix.len())
254 {
255 new_len -= prefix.len();
256 std::memmove(converted.data() + new_len,
257 text.data() + prefix.start, prefix.byte_len());
258 }
259
260 if (delimiter != String::npos)
261 {
262 std::memcpy(converted.data() + delimiter, ELEM_HIDE_EMULATION_DELIMITER,
263 ELEM_HIDE_EMULATION_DELIMITER_LEN * sizeof(String::value_type));
264 }
265
266 return converted;
267 }
268
269 namespace
270 {
127 static constexpr String::value_type OPENING_CURLY_REPLACEMENT[] = u"\\7B "; 271 static constexpr String::value_type OPENING_CURLY_REPLACEMENT[] = u"\\7B ";
128 static constexpr String::value_type CLOSING_CURLY_REPLACEMENT[] = u"\\7D "; 272 static constexpr String::value_type CLOSING_CURLY_REPLACEMENT[] = u"\\7D ";
129 static constexpr String::size_type CURLY_REPLACEMENT_SIZE = sizeof(OPENING_CUR LY_REPLACEMENT) / sizeof(OPENING_CURLY_REPLACEMENT[0]) - 1; 273 static constexpr String::size_type CURLY_REPLACEMENT_SIZE = str_length_of(OPEN ING_CURLY_REPLACEMENT);
130 274
131 OwnedString EscapeCurlies(String::size_type replacementCount, 275 OwnedString EscapeCurlies(String::size_type replacementCount,
132 const DependentString& str) 276 const DependentString& str)
133 { 277 {
134 OwnedString result(str.length() + replacementCount * (CURLY_REPLACEMENT_SIZE - 1)); 278 OwnedString result(str.length() + replacementCount * (CURLY_REPLACEMENT_SIZE - 1));
135 279
136 String::value_type* current = result.data(); 280 String::value_type* current = result.data();
137 for (String::size_type i = 0; i < str.length(); i++) 281 for (String::size_type i = 0; i < str.length(); i++)
138 { 282 {
139 switch(str[i]) 283 switch(str[i])
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 if (item.second && !item.first.empty()) 327 if (item.second && !item.first.empty())
184 { 328 {
185 if (!result.empty()) 329 if (!result.empty())
186 result.append(u','); 330 result.append(u',');
187 result.append(item.first); 331 result.append(item.first);
188 } 332 }
189 } 333 }
190 } 334 }
191 return result; 335 return result;
192 } 336 }
OLDNEW
« no previous file with comments | « compiled/filter/ElemHideBase.h ('k') | compiled/filter/Filter.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld