Index: assets/js/Matcher.jsm |
=================================================================== |
new file mode 100755 |
--- /dev/null |
+++ b/assets/js/Matcher.jsm |
@@ -0,0 +1,381 @@ |
+/* |
+ * This Source Code is subject to the terms of the Mozilla Public License |
+ * version 2.0 (the "License"). You can obtain a copy of the License at |
+ * http://mozilla.org/MPL/2.0/. |
+ */ |
+ |
+// |
+// This file has been generated automatically from Adblock Plus source code |
+// |
+ |
+(function (_patchFunc0) { |
+ function Matcher() { |
+ this.clear(); |
+ } |
+ Matcher.prototype = { |
+ filterByKeyword: null, |
+ keywordByFilter: null, |
+ clear: function () { |
+ this.filterByKeyword = { |
+ __proto__: null |
+ }; |
+ this.keywordByFilter = { |
+ __proto__: null |
+ }; |
+ } |
+ , |
+ add: function (filter) { |
+ if (filter.text in this.keywordByFilter) |
+ return ; |
+ var keyword = this.findKeyword(filter); |
+ switch (typeof this.filterByKeyword[keyword]) { |
+ case "undefined": { |
+ this.filterByKeyword[keyword] = filter.text; |
+ break; |
+ } |
+ case "string": { |
+ this.filterByKeyword[keyword] = [this.filterByKeyword[keyword], filter.text]; |
+ break; |
+ } |
+ default: { |
+ this.filterByKeyword[keyword].push(filter.text); |
+ break; |
+ } |
+ } |
+ this.keywordByFilter[filter.text] = keyword; |
+ } |
+ , |
+ remove: function (filter) { |
+ if (!(filter.text in this.keywordByFilter)) |
+ return ; |
+ var keyword = this.keywordByFilter[filter.text]; |
+ var list = this.filterByKeyword[keyword]; |
+ if (typeof list == "string") |
+ delete this.filterByKeyword[keyword]; |
+ else { |
+ var index = list.indexOf(filter.text); |
+ if (index >= 0) { |
+ list.splice(index, 1); |
+ if (list.length == 1) |
+ this.filterByKeyword[keyword] = list[0]; |
+ } |
+ } |
+ delete this.keywordByFilter[filter.text]; |
+ } |
+ , |
+ findKeyword: function (filter) { |
+ var defaultResult = (filter.contentType & RegExpFilter.typeMap.DONOTTRACK ? "donottrack" : ""); |
+ var text = filter.text; |
+ if (Filter.regexpRegExp.test(text)) |
+ return defaultResult; |
+ if (Filter.optionsRegExp.test(text)) |
+ text = RegExp.leftContext; |
+ if (text.substr(0, 2) == "@@") |
+ text = text.substr(2); |
+ var candidates = text.toLowerCase().match(/[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/g); |
+ if (!candidates) |
+ return defaultResult; |
+ var hash = this.filterByKeyword; |
+ var result = defaultResult; |
+ var resultCount = 16777215; |
+ var resultLength = 0; |
+ for (var i = 0, l = candidates.length; |
+ i < l; i++) { |
+ var candidate = candidates[i].substr(1); |
+ var count; |
+ switch (typeof hash[candidate]) { |
+ case "undefined": { |
+ count = 0; |
+ break; |
+ } |
+ case "string": { |
+ count = 1; |
+ break; |
+ } |
+ default: { |
+ count = hash[candidate].length; |
+ break; |
+ } |
+ } |
+ if (count < resultCount || (count == resultCount && candidate.length > resultLength)) { |
+ result = candidate; |
+ resultCount = count; |
+ resultLength = candidate.length; |
+ } |
+ } |
+ return result; |
+ } |
+ , |
+ hasFilter: function (filter) { |
+ return (filter.text in this.keywordByFilter); |
+ } |
+ , |
+ getKeywordForFilter: function (filter) { |
+ if (filter.text in this.keywordByFilter) |
+ return this.keywordByFilter[filter.text]; |
+ else |
+ return null; |
+ } |
+ , |
+ _checkEntryMatch: function (keyword, location, contentType, docDomain, thirdParty) { |
+ var list = this.filterByKeyword[keyword]; |
+ if (typeof list == "string") { |
+ var filter = Filter.knownFilters[list]; |
+ if (!filter) { |
+ delete this.filterByKeyword[keyword]; |
+ return null; |
+ } |
+ return (filter.matches(location, contentType, docDomain, thirdParty) ? filter : null); |
+ } |
+ else { |
+ for (var i = 0; |
+ i < list.length; i++) { |
+ var filter = Filter.knownFilters[list[i]]; |
+ if (!filter) { |
+ if (list.length == 1) { |
+ delete this.filterByKeyword[keyword]; |
+ return null; |
+ } |
+ else { |
+ list.splice(i--, 1); |
+ continue; |
+ } |
+ } |
+ if (filter.matches(location, contentType, docDomain, thirdParty)) |
+ return filter; |
+ } |
+ return null; |
+ } |
+ } |
+ , |
+ matchesAny: function (location, contentType, docDomain, thirdParty) { |
+ var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); |
+ if (candidates === null) |
+ candidates = []; |
+ if (contentType == "DONOTTRACK") |
+ candidates.unshift("donottrack"); |
+ else |
+ candidates.push(""); |
+ for (var i = 0, l = candidates.length; |
+ i < l; i++) { |
+ var substr = candidates[i]; |
+ if (substr in this.filterByKeyword) { |
+ var result = this._checkEntryMatch(substr, location, contentType, docDomain, thirdParty); |
+ if (result) |
+ return result; |
+ } |
+ } |
+ return null; |
+ } |
+ , |
+ toCache: function (cache) { |
+ cache.filterByKeyword = this.filterByKeyword; |
+ } |
+ , |
+ fromCache: function (cache) { |
+ this.filterByKeyword = cache.filterByKeyword; |
+ this.filterByKeyword.__proto__ = null; |
+ delete this.keywordByFilter; |
+ this.__defineGetter__("keywordByFilter", function () { |
+ var result = { |
+ __proto__: null |
+ }; |
+ for (var k in this.filterByKeyword) { |
+ var list = this.filterByKeyword[k]; |
+ if (typeof list == "string") |
+ result[list] = k; |
+ else |
+ for (var i = 0, l = list.length; |
+ i < l; i++) |
+ result[list[i]] = k; |
+ } |
+ return this.keywordByFilter = result; |
+ } |
+ ); |
+ this.__defineSetter__("keywordByFilter", function (value) { |
+ delete this.keywordByFilter; |
+ return this.keywordByFilter = value; |
+ } |
+ ); |
+ } |
+ |
+ }; |
+ function CombinedMatcher() { |
+ this.blacklist = new Matcher(); |
+ this.whitelist = new Matcher(); |
+ this.keys = { |
+ __proto__: null |
+ }; |
+ this.resultCache = { |
+ __proto__: null |
+ }; |
+ } |
+ CombinedMatcher.maxCacheEntries = 1000; |
+ CombinedMatcher.prototype = { |
+ blacklist: null, |
+ whitelist: null, |
+ keys: null, |
+ resultCache: null, |
+ cacheEntries: 0, |
+ clear: function () { |
+ this.blacklist.clear(); |
+ this.whitelist.clear(); |
+ this.keys = { |
+ __proto__: null |
+ }; |
+ this.resultCache = { |
+ __proto__: null |
+ }; |
+ this.cacheEntries = 0; |
+ } |
+ , |
+ add: function (filter) { |
+ if (filter instanceof WhitelistFilter) { |
+ if (filter.siteKeys) { |
+ for (var i = 0; |
+ i < filter.siteKeys.length; i++) |
+ this.keys[filter.siteKeys[i]] = filter.text; |
+ } |
+ else |
+ this.whitelist.add(filter); |
+ } |
+ else |
+ this.blacklist.add(filter); |
+ if (this.cacheEntries > 0) { |
+ this.resultCache = { |
+ __proto__: null |
+ }; |
+ this.cacheEntries = 0; |
+ } |
+ } |
+ , |
+ remove: function (filter) { |
+ if (filter instanceof WhitelistFilter) { |
+ if (filter.siteKeys) { |
+ for (var i = 0; |
+ i < filter.siteKeys.length; i++) |
+ delete this.keys[filter.siteKeys[i]]; |
+ } |
+ else |
+ this.whitelist.remove(filter); |
+ } |
+ else |
+ this.blacklist.remove(filter); |
+ if (this.cacheEntries > 0) { |
+ this.resultCache = { |
+ __proto__: null |
+ }; |
+ this.cacheEntries = 0; |
+ } |
+ } |
+ , |
+ findKeyword: function (filter) { |
+ if (filter instanceof WhitelistFilter) |
+ return this.whitelist.findKeyword(filter); |
+ else |
+ return this.blacklist.findKeyword(filter); |
+ } |
+ , |
+ hasFilter: function (filter) { |
+ if (filter instanceof WhitelistFilter) |
+ return this.whitelist.hasFilter(filter); |
+ else |
+ return this.blacklist.hasFilter(filter); |
+ } |
+ , |
+ getKeywordForFilter: function (filter) { |
+ if (filter instanceof WhitelistFilter) |
+ return this.whitelist.getKeywordForFilter(filter); |
+ else |
+ return this.blacklist.getKeywordForFilter(filter); |
+ } |
+ , |
+ isSlowFilter: function (filter) { |
+ var matcher = (filter instanceof WhitelistFilter ? this.whitelist : this.blacklist); |
+ if (matcher.hasFilter(filter)) |
+ return !matcher.getKeywordForFilter(filter); |
+ else |
+ return !matcher.findKeyword(filter); |
+ } |
+ , |
+ matchesAnyInternal: function (location, contentType, docDomain, thirdParty) { |
+ var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); |
+ if (candidates === null) |
+ candidates = []; |
+ if (contentType == "DONOTTRACK") |
+ candidates.unshift("donottrack"); |
+ else |
+ candidates.push(""); |
+ var blacklistHit = null; |
+ for (var i = 0, l = candidates.length; |
+ i < l; i++) { |
+ var substr = candidates[i]; |
+ if (substr in this.whitelist.filterByKeyword) { |
+ var result = this.whitelist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty); |
+ if (result) |
+ return result; |
+ } |
+ if (substr in this.blacklist.filterByKeyword && blacklistHit === null) |
+ blacklistHit = this.blacklist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty); |
+ } |
+ return blacklistHit; |
+ } |
+ , |
+ matchesAny: function (location, contentType, docDomain, thirdParty) { |
+ var key = location + " " + contentType + " " + docDomain + " " + thirdParty; |
+ if (key in this.resultCache) |
+ return this.resultCache[key]; |
+ var result = this.matchesAnyInternal(location, contentType, docDomain, thirdParty); |
+ if (this.cacheEntries >= CombinedMatcher.maxCacheEntries) { |
+ this.resultCache = { |
+ __proto__: null |
+ }; |
+ this.cacheEntries = 0; |
+ } |
+ this.resultCache[key] = result; |
+ this.cacheEntries++; |
+ return result; |
+ } |
+ , |
+ matchesByKey: function (location, key, docDomain) { |
+ key = key.toUpperCase(); |
+ if (key in this.keys) { |
+ var filter = Filter.knownFilters[this.keys[key]]; |
+ if (filter && filter.matches(location, "DOCUMENT", docDomain, false)) |
+ return filter; |
+ else |
+ return null; |
+ } |
+ else |
+ return null; |
+ } |
+ , |
+ toCache: function (cache) { |
+ cache.matcher = { |
+ whitelist: { |
+ |
+ }, |
+ blacklist: { |
+ |
+ }, |
+ keys: this.keys |
+ }; |
+ this.whitelist.toCache(cache.matcher.whitelist); |
+ this.blacklist.toCache(cache.matcher.blacklist); |
+ } |
+ , |
+ fromCache: function (cache) { |
+ this.whitelist.fromCache(cache.matcher.whitelist); |
+ this.blacklist.fromCache(cache.matcher.blacklist); |
+ this.keys = cache.matcher.keys; |
+ } |
+ |
+ }; |
+ var defaultMatcher = new CombinedMatcher(); |
+ if (typeof _patchFunc0 != "undefined") |
+ eval("(" + _patchFunc0.toString() + ")()"); |
+ window.Matcher = Matcher; |
+ window.CombinedMatcher = CombinedMatcher; |
+ window.defaultMatcher = defaultMatcher; |
+} |
+)(window.MatcherPatch); |