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

Delta Between Two Patch Sets: compiled/filter/ElemHideBase.cpp

Issue 29595633: Issue 5870 - Implement the new ElemHideEmulation filter type (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: Created Nov. 2, 2017, 11:42 p.m.
Right Patch Set: Deal with ill formed filters. Created Feb. 14, 2018, 5:05 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « compiled/filter/ElemHideBase.h ('k') | compiled/filter/Filter.cpp » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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>
19
18 #include "ElemHideBase.h" 20 #include "ElemHideBase.h"
19 #include "../StringScanner.h" 21 #include "../StringScanner.h"
22 #include "../Utils.h"
23
24 ABP_NS_USING
20 25
21 namespace 26 namespace
22 { 27 {
23 void NormalizeWhitespace(DependentString& text, String::size_type& domainsEnd, 28 void NormalizeWhitespace(DependentString& text, String::size_type& domainsEnd,
24 String::size_type& selectorStart) 29 String::size_type& selectorStart)
25 { 30 {
26 // 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
27 // 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
28 // accordingly. 33 // accordingly.
29 34
(...skipping 10 matching lines...) Expand all
40 // Only spaces before selectorStart position should be removed. 45 // Only spaces before selectorStart position should be removed.
41 if (pos < selectorStart && text[pos] == ' ') 46 if (pos < selectorStart && text[pos] == ' ')
42 delta++; 47 delta++;
43 else 48 else
44 text[pos - delta] = text[pos]; 49 text[pos - delta] = text[pos];
45 } 50 }
46 selectorStart -= delta; 51 selectorStart -= delta;
47 52
48 text.reset(text, 0, len - delta); 53 text.reset(text, 0, len - delta);
49 } 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);
50 } 67 }
51 68
52 ElemHideBase::ElemHideBase(Type type, const String& text, const ElemHideData& da ta) 69 ElemHideBase::ElemHideBase(Type type, const String& text, const ElemHideData& da ta)
53 : ActiveFilter(type, text, false), mData(data) 70 : ActiveFilter(type, text, false), mData(data)
54 { 71 {
55 if (mData.HasDomains()) 72 if (mData.HasDomains())
56 ParseDomains(mData.GetDomainsSource(mText), u','); 73 ParseDomains(mData.GetDomainsSource(mText), u',');
57 } 74 }
58 75
59 Filter::Type ElemHideBase::Parse(DependentString& text, ElemHideData& data) 76 Filter::Type ElemHideBase::Parse(DependentString& text, ElemHideData& data, bool & needConversion)
60 { 77 {
78 needConversion = false;
79
61 StringScanner scanner(text); 80 StringScanner scanner(text);
62 81
63 // Domains part 82 // Domains part
64 bool seenSpaces = false; 83 bool seenSpaces = false;
65 while (!scanner.done()) 84 while (!scanner.done())
66 { 85 {
67 String::value_type next = scanner.next(); 86 String::value_type next = scanner.next();
68 if (next == u'#') 87 if (next == u'#')
69 { 88 {
70 data.mDomainsEnd = scanner.position(); 89 data.mDomainsEnd = scanner.position();
(...skipping 28 matching lines...) Expand all
99 return Type::UNKNOWN; 118 return Type::UNKNOWN;
100 119
101 // Selector part 120 // Selector part
102 121
103 // Selector shouldn't be empty 122 // Selector shouldn't be empty
104 seenSpaces |= scanner.skip(u' '); 123 seenSpaces |= scanner.skip(u' ');
105 if (scanner.done()) 124 if (scanner.done())
106 return Type::UNKNOWN; 125 return Type::UNKNOWN;
107 126
108 data.mSelectorStart = scanner.position() + 1; 127 data.mSelectorStart = scanner.position() + 1;
109 while (!scanner.done())
110 {
111 switch (scanner.next())
112 {
113 case u'{':
114 case u'}':
115 return Type::UNKNOWN;
116 }
117 }
118 128
119 // 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
120 if (seenSpaces) 130 if (seenSpaces)
121 NormalizeWhitespace(text, data.mDomainsEnd, data.mSelectorStart); 131 NormalizeWhitespace(text, data.mDomainsEnd, data.mSelectorStart);
122 DependentString(text, 0, data.mDomainsEnd).toLower(); 132 DependentString(text, 0, data.mDomainsEnd).toLower();
123 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
124 if (exception) 143 if (exception)
125 return Type::ELEMHIDEEXCEPTION; 144 return Type::ELEMHIDEEXCEPTION;
126 145
127 if (emulation) 146 if (emulation)
128 return Type::ELEMHIDEEMULATION; 147 return Type::ELEMHIDEEMULATION;
129 148
130 return Type::ELEMHIDE; 149 return Type::ELEMHIDE;
150 }
151
152 namespace
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 if (properties.start != index)
195 return DependentString();
196
197 quote = c;
198 properties.start = index + 1;
199 }
200 else if (quote == c)
201 {
202 // end of quoted.
203 quote = 0;
204 properties.end = index;
205 }
206 break;
207 case u']':
208 if (quote == 0)
209 {
210 if (properties.end == 0)
211 return DependentString();
212 if (properties.end + 1 != index)
213 return DependentString();
214 suffix.start = index + 1;
215 }
216 break;
217 default:
218 break;
219 }
220 }
221
222 if (suffix.start == at)
sergei 2018/02/27 10:56:53 Just for reference, I think it (what the whole for
223 return DependentString();
224
225 String::size_type delimiter = text.find(ELEM_HIDE_DELIMITER, 0,
226 ELEM_HIDE_DELIMITER_LEN);
227 // +1 for the replacement of "##" by "#?#"
228 if (delimiter != text.npos)
229 at++;
230 auto new_len = at + prefix.len() + PROPS_SELECTOR_LEN + properties.len() + 1 / * ) */ + suffix.len();
231
232 assert2(new_len + 1 == length || (delimiter == text.npos && new_len + 2 == len gth), u"Inconsistent length in filter conversion."_str);
sergei 2018/02/27 10:56:53 not important just for reference length == new_len
hub 2018/02/27 13:32:30 Acknowledged.
233
234 DependentString converted(text, 0, new_len);
235
236 if (suffix.len())
237 {
238 new_len -= suffix.len();
239 std::memmove(converted.data() + new_len,
240 text.data() + suffix.start,
241 suffix.byte_len());
242 }
243 new_len--;
244 // here we need to move the properties before inserting the ')'
245 auto parens = new_len;
246 if (properties.len())
247 {
248 new_len -= properties.len();
249 std::memmove(converted.data() + new_len,
250 text.data() + properties.start, properties.byte_len());
251 }
252 converted[parens] = u')';
253
254 new_len -= PROPS_SELECTOR_LEN;
255 std::memcpy(converted.data() + new_len,
256 PROPS_SELECTOR,
257 PROPS_SELECTOR_LEN * sizeof(String::value_type));
258 if (prefix.len())
259 {
260 new_len -= prefix.len();
261 std::memmove(converted.data() + new_len,
262 text.data() + prefix.start, prefix.byte_len());
263 }
264
265 if (delimiter != String::npos)
266 {
267 std::memcpy(converted.data() + delimiter, ELEM_HIDE_EMULATION_DELIMITER,
268 ELEM_HIDE_EMULATION_DELIMITER_LEN * sizeof(String::value_type));
269 }
270
271 return converted;
272 }
273
274 namespace
275 {
276 static constexpr String::value_type OPENING_CURLY_REPLACEMENT[] = u"\\7B ";
277 static constexpr String::value_type CLOSING_CURLY_REPLACEMENT[] = u"\\7D ";
278 static constexpr String::size_type CURLY_REPLACEMENT_SIZE = str_length_of(OPEN ING_CURLY_REPLACEMENT);
279
280 OwnedString EscapeCurlies(String::size_type replacementCount,
281 const DependentString& str)
282 {
283 OwnedString result(str.length() + replacementCount * (CURLY_REPLACEMENT_SIZE - 1));
284
285 String::value_type* current = result.data();
286 for (String::size_type i = 0; i < str.length(); i++)
287 {
288 switch(str[i])
289 {
290 case u'}':
291 std::memcpy(current, CLOSING_CURLY_REPLACEMENT,
292 sizeof(String::value_type) * CURLY_REPLACEMENT_SIZE);
293 current += CURLY_REPLACEMENT_SIZE;
294 break;
295 case u'{':
296 std::memcpy(current, OPENING_CURLY_REPLACEMENT,
297 sizeof(String::value_type) * CURLY_REPLACEMENT_SIZE);
298 current += CURLY_REPLACEMENT_SIZE;
299 break;
300 default:
301 *current = str[i];
302 current++;
303 break;
304 }
305 }
306
307 return result;
308 }
309 }
310
311 OwnedString ElemHideBase::GetSelector() const
312 {
313 const DependentString selector = mData.GetSelector(mText);
314 String::size_type replacementCount = 0;
315 for (String::size_type i = 0; i < selector.length(); i++)
316 if (selector[i] == '}' || selector[i] == '{')
317 replacementCount++;
318 if (replacementCount)
319 return EscapeCurlies(replacementCount, selector);
320
321 return OwnedString(selector);
131 } 322 }
132 323
133 OwnedString ElemHideBase::GetSelectorDomain() const 324 OwnedString ElemHideBase::GetSelectorDomain() const
134 { 325 {
135 /* TODO this is inefficient */ 326 /* TODO this is inefficient */
136 OwnedString result; 327 OwnedString result;
137 if (mDomains) 328 if (mDomains)
138 { 329 {
139 for (const auto& item : *mDomains) 330 for (const auto& item : *mDomains)
140 { 331 {
141 if (item.second && !item.first.empty()) 332 if (item.second && !item.first.empty())
142 { 333 {
143 if (!result.empty()) 334 if (!result.empty())
144 result.append(u','); 335 result.append(u',');
145 result.append(item.first); 336 result.append(item.first);
146 } 337 }
147 } 338 }
148 } 339 }
149 return result; 340 return result;
150 } 341 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld