Index: chrome/content/elemHideEmulation.js |
=================================================================== |
--- a/chrome/content/elemHideEmulation.js |
+++ b/chrome/content/elemHideEmulation.js |
@@ -14,17 +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/>. |
*/ |
/* globals filterToRegExp */ |
"use strict"; |
-let propertySelectorRegExp = /\[-abp-properties=(["'])([^"']+)\1\]/; |
+const abpSelectorRegexp = /:-abp-([\w-]+)\(/i; |
function splitSelector(selector) |
{ |
if (selector.indexOf(",") == -1) |
return [selector]; |
let selectors = []; |
let start = 0; |
@@ -145,36 +145,80 @@ ElemHideEmulation.prototype = { |
apply() |
{ |
this.getFiltersFunc(patterns => |
{ |
this.patterns = []; |
for (let pattern of patterns) |
{ |
- let match = propertySelectorRegExp.exec(pattern.selector); |
- if (!match) |
+ let match = abpSelectorRegexp.exec(pattern.selector); |
+ if (!match || match[1] != "properties") |
+ { |
+ console.error(new SyntaxError( |
+ `Failed to parse Adblock Plus selector ${pattern.selector}, ` + |
+ `invalid pseudo-class :-abp-${match[1]}().` |
+ )); |
continue; |
+ } |
- let propertyExpression = match[2]; |
+ let expressionStart = match.index + match[0].length; |
+ let parens = 1; |
+ let quote = null; |
+ let i; |
+ for (i = expressionStart; i < pattern.selector.length; i++) |
+ { |
+ let c = pattern.selector[i]; |
+ if (c == "\\") |
+ { |
+ // Ignore escaped characters |
+ i++; |
+ } |
+ else if (quote) |
+ { |
+ if (c == quote) |
+ quote = null; |
+ } |
+ else if (c == "'" || c == '"') |
+ quote = c; |
+ else if (c == "(") |
+ parens++; |
+ else if (c == ")") |
+ { |
+ parens--; |
+ if (parens == 0) |
+ break; |
+ } |
+ } |
+ |
+ if (parens > 0) |
+ { |
+ console.error(new SyntaxError( |
+ `Failed to parse Adblock Plus selector ${pattern.selector} ` + |
+ "due to unmatched parentheses." |
+ )); |
+ continue; |
+ } |
+ |
+ let propertyExpression = pattern.selector.substring(expressionStart, i); |
let regexpString; |
if (propertyExpression.length >= 2 && propertyExpression[0] == "/" && |
propertyExpression[propertyExpression.length - 1] == "/") |
{ |
regexpString = propertyExpression.slice(1, -1) |
.replace("\\x7B ", "{").replace("\\x7D ", "}"); |
} |
else |
regexpString = filterToRegExp(propertyExpression); |
this.patterns.push({ |
text: pattern.text, |
regexp: new RegExp(regexpString, "i"), |
prefix: pattern.selector.substr(0, match.index), |
- suffix: pattern.selector.substr(match.index + match[0].length) |
+ suffix: pattern.selector.substr(i + 1) |
}); |
} |
if (this.patterns.length > 0) |
{ |
let {document} = this.window; |
this.addSelectors(document.styleSheets); |
document.addEventListener("load", this.onLoad.bind(this), true); |