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