diff --git a/src/js/cosmetic-filtering.js b/src/js/cosmetic-filtering.js index dc7e3bcd0..e2ea564d4 100644 --- a/src/js/cosmetic-filtering.js +++ b/src/js/cosmetic-filtering.js @@ -244,7 +244,6 @@ var FilterParser = function() { this.hostnames = []; this.invalid = false; this.cosmetic = true; - this.reParser = /^([^#]*?)(##|#@#)(.+)$/; this.reScriptContains = /^script:contains\(.+?\)$/; }; @@ -265,14 +264,59 @@ FilterParser.prototype.parse = function(raw) { // important! this.reset(); - var matches = this.reParser.exec(raw); - if ( matches === null || matches.length !== 4 ) { + // Find the bounds of the anchor. + var lpos = raw.indexOf('#'); + if ( lpos === -1 ) { + this.cosmetic = false; + return this; + } + var rpos = raw.indexOf('#', lpos + 1); + if ( rpos === -1 ) { + this.cosmetic = false; + return this; + } + + // Coarse-check that the anchor is valid. + // `##`: l = 1 + // `#@#`, `#$#`, `#%#`: l = 2 + // `#@$#`, `#@%#`: l = 3 + if ( (rpos - lpos) > 3 ) { + this.cosmetic = false; + return this; + } + + // Find out type of cosmetic filter. + // Exception filter? + if ( raw.charCodeAt(lpos + 1) === 0x40 /* '@' */ ) { + this.unhide = 1; + } + + // https://github.com/gorhill/uBlock/issues/952 + // Find out whether we are dealing with an Adguard-specific cosmetic + // filter, and if so, discard the filter. + var cCode = raw.charCodeAt(rpos - 1); + if ( cCode !== 0x23 /* '#' */ && cCode !== 0x40 /* '@' */ ) { + // We have an Adguard cosmetic filter if and only if the character is + // `$` or `%`, otherwise it's not a cosmetic filter. + if ( cCode === 0x24 /* '$' */ || cCode === 0x25 /* '%' */ ) { + this.invalid = true; + } else { + this.cosmetic = false; + } + return this; + } + + // Extract the hostname(s). + if ( lpos !== 0 ) { + this.prefix = raw.slice(0, lpos); + } + + // Extract the selector. + this.suffix = raw.slice(rpos + 1); + if ( this.suffix.length === 0 ) { this.cosmetic = false; return this; } - this.prefix = matches[1].trim(); - this.unhide = matches[2].charAt(1) === '@' ? 1 : 0; - this.suffix = matches[3].trim(); // Cosmetic filters with explicit style properties can apply only: // - to specific cosmetic filters (those which apply to a specific site) @@ -659,6 +703,7 @@ FilterContainer.prototype.compile = function(s, out) { return false; } if ( parsed.invalid ) { + //console.error("uBlock Origin> discarding invalid cosmetic filter '%s'", s); return true; } @@ -847,7 +892,7 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) { var line, fields, filter, key, bucket; while ( lineBeg < textEnd ) { - if ( text.charAt(lineBeg) !== 'c' ) { + if ( text.charCodeAt(lineBeg) !== 0x63 /* 'c' */ ) { return lineBeg; } lineEnd = text.indexOf('\n', lineBeg); @@ -961,7 +1006,7 @@ FilterContainer.prototype.skipCompiledContent = function(text, lineBeg) { var textEnd = text.length; while ( lineBeg < textEnd ) { - if ( text.charAt(lineBeg) !== 'c' ) { + if ( text.charCodeAt(lineBeg) !== 0x63 /* 'c' */ ) { return lineBeg; } lineEnd = text.indexOf('\n', lineBeg); diff --git a/src/js/static-net-filtering.js b/src/js/static-net-filtering.js index 5764adfa7..479960a34 100644 --- a/src/js/static-net-filtering.js +++ b/src/js/static-net-filtering.js @@ -1557,6 +1557,12 @@ FilterParser.prototype.parse = function(raw) { if ( s.charAt(0) !== '/' || s.slice(-1) !== '/' ) { pos = s.lastIndexOf('$'); if ( pos !== -1 ) { + // https://github.com/gorhill/uBlock/issues/952 + // Discard Adguard-specific `$$` filters. + if ( s.indexOf('$$') !== -1 ) { + this.unsupported = true; + return this; + } this.parseOptions(s.slice(pos + 1)); s = s.slice(0, pos); } @@ -1917,12 +1923,6 @@ FilterContainer.prototype.compile = function(raw, out) { return false; } - // Ignore comments - var c = s.charAt(0); - if ( c === '[' || c === '!' ) { - return false; - } - var parsed = this.filterParser.parse(s); // Ignore element-hiding filters @@ -2070,7 +2070,7 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg) { var line, fields, bucket, entry, factory, filter; while ( lineBeg < textEnd ) { - if ( text.charAt(lineBeg) !== 'n' ) { + if ( text.charCodeAt(lineBeg) !== 0x6E /* 'n' */ ) { return lineBeg; } lineEnd = text.indexOf('\n', lineBeg);