| 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); |