diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CallbackWrapper.jsm | 14 | ||||
-rw-r--r-- | lib/CookieCache.jsm | 162 | ||||
-rw-r--r-- | lib/FrameModule.jsm | 74 | ||||
-rw-r--r-- | lib/HostMap.jsm | 28 | ||||
-rw-r--r-- | lib/HttpRequestHeaders.jsm | 18 | ||||
-rw-r--r-- | lib/LiquidDict.jsm | 90 | ||||
-rw-r--r-- | lib/PendingRequests.jsm | 100 | ||||
-rw-r--r-- | lib/PublicSuffixList.jsm | 268 | ||||
-rw-r--r-- | lib/Punycode.jsm | 262 | ||||
-rw-r--r-- | lib/RowSnapshot.jsm | 2 | ||||
-rw-r--r-- | lib/Tools.jsm | 112 | ||||
-rw-r--r-- | lib/UriTools.jsm | 390 | ||||
-rw-r--r-- | lib/publicsuffixlist.js | 556 | ||||
-rw-r--r-- | lib/punycode.js | 1050 |
14 files changed, 1562 insertions, 1564 deletions
diff --git a/lib/CallbackWrapper.jsm b/lib/CallbackWrapper.jsm index 8c07732..739be97 100644 --- a/lib/CallbackWrapper.jsm +++ b/lib/CallbackWrapper.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2022 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -28,7 +28,7 @@ var EXPORTED_SYMBOLS = ['CallbackWrapper']; var junkyard = []; var CallbackWrapper = function (messageManager, channelName, - listenerId, requestId) { + listenerId, requestId) { // This allows to avoid creating a closure for every single // message which expects an answer. Having a closure created // each time a message is processed has been always bothering @@ -52,7 +52,7 @@ var CallbackWrapper = function (messageManager, channelName, }; CallbackWrapper.factory = function (messageManager, channelName, - listenerId, requestId) { + listenerId, requestId) { let wrapper = junkyard.pop(); if (wrapper) { wrapper.init(messageManager, channelName, listenerId, requestId); @@ -60,11 +60,11 @@ CallbackWrapper.factory = function (messageManager, channelName, } return new CallbackWrapper(messageManager, channelName, - listenerId, requestId); + listenerId, requestId); }; CallbackWrapper.prototype.init = function (messageManager, channelName, - listenerId, requestId) { + listenerId, requestId) { this.messageManager = messageManager; this.channelName = channelName; this.listenerId = listenerId; @@ -86,7 +86,7 @@ CallbackWrapper.prototype.proxy = function (response) { // Mark for reuse this.messageManager = this.channelName = - this.requestId = this.listenerId = null; + this.requestId = this.listenerId = null; junkyard.push(this); }; diff --git a/lib/CookieCache.jsm b/lib/CookieCache.jsm index c3badb4..e925736 100644 --- a/lib/CookieCache.jsm +++ b/lib/CookieCache.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2022 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -61,111 +61,111 @@ CookieEntry.prototype.dispose = function () { var CookieUtils = { keyFromCookie: function (cookie) { - let cb = []; - - cb[0] = cookie.secure ? 'https' : 'http'; - cb[1] = '://'; - cb[2] = cookie.domain.charAt(0) === '.' ? - cookie.domain.slice(1) : - cookie.domain; - cb[3] = cookie.path; - cb[4] = '{'; - cb[5] = cookie.session ? 'session' : 'persistent'; - cb[6] = '-cookie:'; - cb[7] = cookie.name; - cb[8] = '}'; - - return cb.join(''); + let cb = []; + + cb[0] = cookie.secure ? 'https' : 'http'; + cb[1] = '://'; + cb[2] = cookie.domain.charAt(0) === '.' ? + cookie.domain.slice(1) : + cookie.domain; + cb[3] = cookie.path; + cb[4] = '{'; + cb[5] = cookie.session ? 'session' : 'persistent'; + cb[6] = '-cookie:'; + cb[7] = cookie.name; + cb[8] = '}'; + + return cb.join(''); }, keyFromURL: function (url, type, name) { - if (typeof url !== 'object') { - throw new Error('Invalid URL parameter'); - } - - let cb = []; - - cb[0] = url.scheme; - cb[1] = '://'; - cb[2] = url.hostname; - cb[3] = url.path; - cb[4] = '{'; - cb[5] = type; - cb[6] = '-cookie:'; - cb[7] = name; - cb[8] = '}'; - - return cb.join(''); + if (typeof url !== 'object') { + throw new Error('Invalid URL parameter'); + } + + let cb = []; + + cb[0] = url.scheme; + cb[1] = '://'; + cb[2] = url.hostname; + cb[3] = url.path; + cb[4] = '{'; + cb[5] = type; + cb[6] = '-cookie:'; + cb[7] = name; + cb[8] = '}'; + + return cb.join(''); }, urlFromEntry: function (entry) { - if (!entry) { - return ''; - } + if (!entry) { + return ''; + } - return (entry.secure ? 'https://' : 'http://') - + entry.hostname - + entry.path; + return (entry.secure ? 'https://' : 'http://') + + entry.hostname + + entry.path; }, matchDomains: function (key, allHosts) { - let entry = CookieCache.get(key); + let entry = CookieCache.get(key); - if (entry === undefined) { - return false; - } + if (entry === undefined) { + return false; + } - if (allHosts.indexOf(' '+entry.hostname+' ') < 0) { - if (!entry.anySubdomain) { - return false; - } + if (allHosts.indexOf(' '+entry.hostname+' ') < 0) { + if (!entry.anySubdomain) { + return false; + } - if (allHosts.indexOf('.'+entry.hostname+' ') < 0) { - return false; - } - } + if (allHosts.indexOf('.'+entry.hostname+' ') < 0) { + return false; + } + } - return true; + return true; }, }; var CookieCache = { add: function (cookie) { - let key = CookieUtils.keyFromCookie(cookie); - let value = dict.get(key); - - if (value === undefined) { - value = junkyard.pop(); - if (value) { - value.init(cookie); - } else { - value = new CookieEntry(cookie); - } - dict.set(key, value); - } - - return value; + let key = CookieUtils.keyFromCookie(cookie); + let value = dict.get(key); + + if (value === undefined) { + value = junkyard.pop(); + if (value) { + value.init(cookie); + } else { + value = new CookieEntry(cookie); + } + dict.set(key, value); + } + + return value; }, addVector: function (vector) { - for (let i=vector.length-1; i>=0; --i) { - CookieCache.add(vector[i]); - } + for (let i=vector.length-1; i>=0; --i) { + CookieCache.add(vector[i]); + } }, remove: function (cookie) { - let value = dict.get(cookie); - if (value === undefined) { - return false; - } + let value = dict.get(cookie); + if (value === undefined) { + return false; + } - dict.delete(cookie); + dict.delete(cookie); - if (junkyard.length < 25) { - junkyard.push(value.dispose()); - } + if (junkyard.length < 25) { + junkyard.push(value.dispose()); + } - return true; + return true; }, get: function (key) { - return dict.get(key); + return dict.get(key); }, keys: function () { - return dict.keys(); + return dict.keys(); } }; diff --git a/lib/FrameModule.jsm b/lib/FrameModule.jsm index 543013c..7af0e63 100644 --- a/lib/FrameModule.jsm +++ b/lib/FrameModule.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 The µBlock authors - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2022 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -68,10 +68,8 @@ var contentObserver = { cpMessageName: hostName + ':shouldLoad', uniqueSandboxId: 1, modernFirefox: - (Services.appinfo.ID === '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}' - || Services.appinfo.ID === '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}' - || Services.appinfo.ID === '{9184b6fe-4a5c-484d-8b4b-efbfccbfb514}') - && Services.vc.compare(Services.appinfo.version, '44') > 0, + ((Services.appinfo.ID === '{9184b6fe-4a5c-484d-8b4b-efbfccbfb514}') + && Services.vc.compare(Services.appinfo.version, '44') > 0), get componentRegistrar() { return Components.manager.QueryInterface(Ci.nsIComponentRegistrar); @@ -79,14 +77,14 @@ var contentObserver = { get categoryManager() { return Components.classes['@mozilla.org/categorymanager;1'] - .getService(Ci.nsICategoryManager); + .getService(Ci.nsICategoryManager); }, QueryInterface: XPCOMUtils.generateQI([ - Ci.nsIFactory, - Ci.nsIObserver, - Ci.nsIContentPolicy, - Ci.nsISupportsWeakReference + Ci.nsIFactory, + Ci.nsIObserver, + Ci.nsIContentPolicy, + Ci.nsISupportsWeakReference ]), createInstance: function (outer, iid) { @@ -102,16 +100,16 @@ var contentObserver = { if (!this.modernFirefox) { this.componentRegistrar - .registerFactory(this.classID, - this.classDescription, - this.contractID, - this); + .registerFactory(this.classID, + this.classDescription, + this.contractID, + this); this.categoryManager - .addCategoryEntry('content-policy', - this.contractID, - this.contractID, - false, - true); + .addCategoryEntry('content-policy', + this.contractID, + this.contractID, + false, + true); } }, @@ -120,12 +118,12 @@ var contentObserver = { if (!this.modernFirefox) { this.componentRegistrar - .unregisterFactory(this.classID, - this); + .unregisterFactory(this.classID, + this); this.categoryManager - .deleteCategoryEntry('content-policy', - this.contractID, - false); + .deleteCategoryEntry('content-policy', + this.contractID, + false); } }, @@ -222,17 +220,17 @@ var contentObserver = { }; messager.addMessageListener(sandbox._sandboxId_, - sandbox._messageListener_); + sandbox._messageListener_); messager.addMessageListener(hostName + ':broadcast', - sandbox._messageListener_); + sandbox._messageListener_); }; sandbox.removeMessageListener = function () { try { messager.removeMessageListener(sandbox._sandboxId_, - sandbox._messageListener_); + sandbox._messageListener_); messager.removeMessageListener(hostName + ':broadcast', - sandbox._messageListener_); + sandbox._messageListener_); } catch (ex) { // It throws sometimes, mostly when the popup closes } @@ -262,8 +260,8 @@ var contentObserver = { } if (loc.protocol !== 'http:' - && loc.protocol !== 'https:' - && loc.protocol !== 'file:') { + && loc.protocol !== 'https:' + && loc.protocol !== 'file:') { if (loc.protocol === 'chrome:' && loc.host === hostName) { this.initContentScripts(win); } @@ -294,9 +292,9 @@ var contentObserver = { doc.addEventListener('DOMContentLoaded', docReady, true); } else { docReady({ - target: doc, - type: 'DOMContentLoaded', - }); + target: doc, + type: 'DOMContentLoaded', + }); } } }; @@ -326,13 +324,13 @@ LocationChangeListener.prototype.QueryInterface = XPCOMUtils.generateQI([ LocationChangeListener.prototype.onLocationChange = function (webProgress, request, location, flags) { - if (!webProgress.isTopLevel) { + if (!webProgress.isTopLevel) { return; - } - this.messageManager.sendAsyncMessage(locationChangedMessageName, { + } + this.messageManager.sendAsyncMessage(locationChangedMessageName, { url: location.asciiSpec, flags: flags, - }); + }); }; contentObserver.register(); diff --git a/lib/HostMap.jsm b/lib/HostMap.jsm index fddace9..3665ca9 100644 --- a/lib/HostMap.jsm +++ b/lib/HostMap.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2020 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -31,22 +31,22 @@ var map = new Map(); var HostMap = { put: function (key, value) { - if (typeof key !== 'string' || !(value instanceof Ci.nsIURI) - || !key || !value) { - throw new Error('invalid argument(s)'); - } + if (typeof key !== 'string' || !(value instanceof Ci.nsIURI) + || !key || !value) { + throw new Error('invalid argument(s)'); + } - if (map.get(key)) { - return; - } + if (map.get(key)) { + return; + } - map.set(key, value); + map.set(key, value); }, get: function (key) { - if (typeof key !== 'string' || !key) { - throw new Error('invalid argument'); - } + if (typeof key !== 'string' || !key) { + throw new Error('invalid argument'); + } - return map.get(key); + return map.get(key); }, }; diff --git a/lib/HttpRequestHeaders.jsm b/lib/HttpRequestHeaders.jsm index 387eabd..757081f 100644 --- a/lib/HttpRequestHeaders.jsm +++ b/lib/HttpRequestHeaders.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2020-2021 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -34,7 +34,7 @@ var HTTPRequestHeaders = function (channel) { HTTPRequestHeaders.factory = function (channel) { let entry = junkyard.pop(); if (entry) { - return entry.init(channel); + return entry.init(channel); } return new HTTPRequestHeaders(channel); @@ -46,10 +46,10 @@ HTTPRequestHeaders.prototype.init = function (channel) { this.originalHeaderNames = new Array(); channel.visitRequestHeaders({ - visitHeader: function (name, value) { - this.headers.push({name: name, value: value}); - this.originalHeaderNames.push(name); - }.bind(this) + visitHeader: function (name, value) { + this.headers.push({name: name, value: value}); + this.originalHeaderNames.push(name); + }.bind(this) }); return this; @@ -72,7 +72,7 @@ HTTPRequestHeaders.prototype.update = function () { //Clear any headers that were removed for (let name of this.originalHeaderNames) { if (!newHeaderNames.has(name)) { - this.channel.setRequestHeader(name, '', false); + this.channel.setRequestHeader(name, '', false); } } }; @@ -81,7 +81,7 @@ HTTPRequestHeaders.prototype.getHeader = function (name) { try { return this.channel.getRequestHeader(name); } catch (e) { - // Ignore + // Ignore } return ''; diff --git a/lib/LiquidDict.jsm b/lib/LiquidDict.jsm index b45a5d7..c462427 100644 --- a/lib/LiquidDict.jsm +++ b/lib/LiquidDict.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 Raymond Hill - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2020-2021 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -40,13 +40,13 @@ function meltBucket(dict, len, bucket) { --dict.frozenCount; if (bucket.charAt(0) === ' ') { - bucket.trim().split(' ').map(function (e) { - map[e] = true; - }); + bucket.trim().split(' ').map(function (e) { + map[e] = true; + }); } else { - for (let i=0; i<bucket.length; i+=len) { - map[bucket.substring(i, len)] = true; - } + for (let i=0; i<bucket.length; i+=len) { + map[bucket.substring(i, len)] = true; + } } return map; @@ -55,10 +55,10 @@ function meltBucket(dict, len, bucket) { function melt(dict) { let buckets = dict.dict; for (let key in buckets) { - let bucket = buckets[key]; - if (typeof bucket === 'string') { - buckets[key] = meltBucket(dict, key.charCodeAt(0) & 0xFF, bucket); - } + let bucket = buckets[key]; + if (typeof bucket === 'string') { + buckets[key] = meltBucket(dict, key.charCodeAt(0) & 0xFF, bucket); + } } } @@ -69,7 +69,7 @@ function freezeBucket(dict, bucket) { ++dict.frozenCount; if (wlen * words.length < dict.cutoff) { - return ' ' + words.join(' ') + ' '; + return ' ' + words.join(' ') + ' '; } return words.sort().join(''); @@ -78,15 +78,15 @@ function freezeBucket(dict, bucket) { LiquidDict.prototype.makeKey = function (word) { let len = word.length; if (len > 255) { - len = 255; + len = 255; } let i = len >> 2; return String.fromCharCode((word.charCodeAt(0) & 0x03) << 14 - | (word.charCodeAt(i) & 0x03) << 12 - | (word.charCodeAt(i+i) & 0x03) << 10 - | (word.charCodeAt(i+i+i) & 0x03) << 8 - | len); + | (word.charCodeAt(i) & 0x03) << 12 + | (word.charCodeAt(i+i) & 0x03) << 10 + | (word.charCodeAt(i+i+i) & 0x03) << 8 + | len); }; LiquidDict.prototype.test = function (word) { @@ -94,15 +94,15 @@ LiquidDict.prototype.test = function (word) { let bucket = this.dict[key]; if (bucket === undefined) { - return false; + return false; } if (typeof bucket === 'object') { - return bucket[word] !== undefined; + return bucket[word] !== undefined; } if (bucket.charAt(0) === ' ') { - return bucket.indexOf(' ' + word + ' ') >= 0; + return bucket.indexOf(' ' + word + ' ') >= 0; } let len = word.length; @@ -110,16 +110,16 @@ LiquidDict.prototype.test = function (word) { let right = ~~(bucket.length / len + 0.5); while (left < right) { - let i = left + right >> 1; - let needle = bucket.substr(len * i, len); - - if (word < needle) { - right = i; - } else if (word > needle) { - left = i + 1; - } else { - return true; - } + let i = left + right >> 1; + let needle = bucket.substr(len * i, len); + + if (word < needle) { + right = i; + } else if (word > needle) { + left = i + 1; + } else { + return true; + } } return false; @@ -128,26 +128,26 @@ LiquidDict.prototype.test = function (word) { LiquidDict.prototype.add = function (word) { let key = this.makeKey(word); if (key === undefined) { - return false; + return false; } let bucket = this.dict[key]; if (bucket === undefined) { - this.dict[key] = bucket = {}; - ++this.bucketCount; - bucket[word] = true; - ++this.count; + this.dict[key] = bucket = {}; + ++this.bucketCount; + bucket[word] = true; + ++this.count; - return true; + return true; } else if (typeof bucket === 'string') { - this.dict[key] = bucket = meltBucket(this, word.len, bucket); + this.dict[key] = bucket = meltBucket(this, word.len, bucket); } if (bucket[word] === undefined) { - bucket[word] = true; - ++this.count; + bucket[word] = true; + ++this.count; - return true; + return true; } ++this.duplicateCount; @@ -159,10 +159,10 @@ LiquidDict.prototype.freeze = function () { let buckets = this.dict; for (let key in buckets) { - let bucket = buckets[key]; - if (typeof bucket === 'object') { - buckets[key] = freezeBucket(this, bucket); - } + let bucket = buckets[key]; + if (typeof bucket === 'object') { + buckets[key] = freezeBucket(this, bucket); + } } }; diff --git a/lib/PendingRequests.jsm b/lib/PendingRequests.jsm index a3f72e5..fdb62e2 100644 --- a/lib/PendingRequests.jsm +++ b/lib/PendingRequests.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2020-2021 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -42,55 +42,55 @@ for (let i=0; i<bufferLength; ++i) { var PendingRequestBuffer = { createRequest: function (url) { - // URL to ring buffer index map: - // { k = URL, s = ring buffer indices } - // - // s is a string which character codes map to ring buffer - // indices -- for when the same URL is received multiple times - // by shouldLoadListener() before the existing one is serviced - // by the network request observer. I believe the use of a - // string in lieu of an array reduces memory churning. - let bucket; - let i = writePointer; - writePointer = (i + 1) % bufferLength; - - let req = ringBuffer[i]; - let str = String.fromCharCode(i); - - if (req._key !== '') { - bucket = urlToIndex.get(req._key); - if (bucket.lenght === 1) { - urlToIndex.delete(req._key); - } else { - let pos = bucket.indexOf(str); - urlToIndex.set(req._key, - bucket.slice(0, pos)+bucket.slice(pos+1)); - } - } - - bucket = urlToIndex.get(url); - urlToIndex.set(url, - (bucket === undefined) ? str : bucket + str); - req._key = url; - - return req; + // URL to ring buffer index map: + // { k = URL, s = ring buffer indices } + // + // s is a string which character codes map to ring buffer + // indices -- for when the same URL is received multiple times + // by shouldLoadListener() before the existing one is serviced + // by the network request observer. I believe the use of a + // string in lieu of an array reduces memory churning. + let bucket; + let i = writePointer; + writePointer = (i + 1) % bufferLength; + + let req = ringBuffer[i]; + let str = String.fromCharCode(i); + + if (req._key !== '') { + bucket = urlToIndex.get(req._key); + if (bucket.lenght === 1) { + urlToIndex.delete(req._key); + } else { + let pos = bucket.indexOf(str); + urlToIndex.set(req._key, + bucket.slice(0, pos)+bucket.slice(pos+1)); + } + } + + bucket = urlToIndex.get(url); + urlToIndex.set(url, + (bucket === undefined) ? str : bucket + str); + req._key = url; + + return req; }, lookupRequest: function (url) { - let bucket = urlToIndex.get(url); - if (bucket === undefined) { - return null; - } - - let i = bucket.charCodeAt(0); - if (bucket.length === 1) { - urlToIndex.delete(url); - } else { - urlToIndex.set(url, bucket.slice(1)); - } - - let req = ringBuffer[i]; - req._key = ''; - - return req; + let bucket = urlToIndex.get(url); + if (bucket === undefined) { + return null; + } + + let i = bucket.charCodeAt(0); + if (bucket.length === 1) { + urlToIndex.delete(url); + } else { + urlToIndex.set(url, bucket.slice(1)); + } + + let req = ringBuffer[i]; + req._key = ''; + + return req; }, }; diff --git a/lib/PublicSuffixList.jsm b/lib/PublicSuffixList.jsm index 297ef49..e2ab5b8 100644 --- a/lib/PublicSuffixList.jsm +++ b/lib/PublicSuffixList.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2020-2021 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -44,41 +44,41 @@ function search(store, hostname) { let remainder; if (pos < 0) { - tld = hostname; - remainder = hostname; + tld = hostname; + remainder = hostname; } else { - tld = hostname.slice(pos+1); - remainder = hostname.slice(0, pos); + tld = hostname.slice(pos+1); + remainder = hostname.slice(0, pos); } let sub = store[tld]; if (!sub) { - return false; + return false; } if (typeof sub === 'string') { - return (sub.indexOf(' '+remainder+' ') >= 0); + return (sub.indexOf(' '+remainder+' ') >= 0); } let l = remainder.length; let val = sub[l]; if (!val) { - return false; + return false; } let left = 0; let right = Math.floor(val.length/l+0.5); while (left < right) { - let i = left+right >> 1; - let key = val.substr(l*i, l); - if (remainder < key) { - right = i; - } else if (remainder > key) { - left = i+1; - } else { - return true; - } + let i = left+right >> 1; + let key = val.substr(l*i, l); + if (remainder < key) { + right = i; + } else if (remainder > key) { + left = i+1; + } else { + return true; + } } return false; @@ -86,47 +86,47 @@ function search(store, hostname) { function getPublicSuffix(hostname) { if (!hostname) { - return ''; + return ''; } while (true) { - let pos = hostname.indexOf('.'); - if (pos < 0) { - return hostname; - } + let pos = hostname.indexOf('.'); + if (pos < 0) { + return hostname; + } - if (search(exceptions, hostname)) { - return hostname.slice(pos+1); - } + if (search(exceptions, hostname)) { + return hostname.slice(pos+1); + } - if (search(rules, hostname)) { - return hostname; - } + if (search(rules, hostname)) { + return hostname; + } - if (search(rules, '*'+hostname.slice(pos))) { - return hostname; - } + if (search(rules, '*'+hostname.slice(pos))) { + return hostname; + } - hostname = hostname.slice(pos+1); + hostname = hostname.slice(pos+1); } } function getDomain(hostname) { if (!hostname || hostname.charAt(0) == '.') { - return ''; + return ''; } hostname = hostname.toLowerCase(); let suffix = getPublicSuffix(hostname); if (suffix === hostname) { - return ''; + return ''; } let len = hostname.length-suffix.length; let pos = hostname.lastIndexOf('.', hostname.lastIndexOf('.', len) - 1); if (pos <= 0) { - return hostname; + return hostname; } return hostname.slice(pos+1); @@ -134,38 +134,38 @@ function getDomain(hostname) { function crystallize(store) { for (let tld in store) { - if (!store.hasOwnProperty(tld)) { - continue; - } - - let suff = store[tld].join(' '); - if (!suff) { - store[tld] = ''; - continue; - } - - if (suff.length < cutoffLength) { - store[tld] = ' ' + suff + ' '; - continue; - } - - suff = []; - for (let i=store[tld].length-1; i>=0; --i) { - let s = store[tld][i]; - let l = s.length; - if (!suff[l]) { - suff[l] = []; - } - suff[l].push(s); - } - - for (let i=suff.length-1; i>=0; --i) { - if (suff[i]) { - suff[i] = suff[i].sort().join(''); - } - } - - store[tld] = suff; + if (!store.hasOwnProperty(tld)) { + continue; + } + + let suff = store[tld].join(' '); + if (!suff) { + store[tld] = ''; + continue; + } + + if (suff.length < cutoffLength) { + store[tld] = ' ' + suff + ' '; + continue; + } + + suff = []; + for (let i=store[tld].length-1; i>=0; --i) { + let s = store[tld][i]; + let l = s.length; + if (!suff[l]) { + suff[l] = []; + } + suff[l].push(s); + } + + for (let i=suff.length-1; i>=0; --i) { + if (suff[i]) { + suff[i] = suff[i].sort().join(''); + } + } + + store[tld] = suff; } return store; @@ -180,61 +180,61 @@ function parse(text, toAscii) { let tend = text.length; while (beg < tend) { - end = text.indexOf('\n', beg); - if (end < 0) { - end = text.indexOf('\r', beg); - if (end < 0) { - end = tend; - } - } - - let line = text.slice(beg, end).trim(); - beg = end+1; - - if (line.length === 0) { - continue; - } - - let pos = line.indexOf('//'); - if (pos >= 0) { - line = line.slice(0, pos); - } - - line = line.trim(); - if (!line) { - continue; - } - - let store; - if (line.charAt(0) == '!') { - store = exceptions; - line = line.slice(1); - } else { - store = rules; - } - - if (reMustPunycode.test(line)) { - line = toAscii(line); - } - - line = line.toLowerCase(); - - let tld; - pos = line.lastIndexOf('.'); - if (pos < 0) { - tld = line; - } else { - tld = line.slice(pos+1); - line = line.slice(0, pos); - } - - if (!store.hasOwnProperty(tld)) { - store[tld] = []; - } - - if (line) { - store[tld].push(line); - } + end = text.indexOf('\n', beg); + if (end < 0) { + end = text.indexOf('\r', beg); + if (end < 0) { + end = tend; + } + } + + let line = text.slice(beg, end).trim(); + beg = end+1; + + if (line.length === 0) { + continue; + } + + let pos = line.indexOf('//'); + if (pos >= 0) { + line = line.slice(0, pos); + } + + line = line.trim(); + if (!line) { + continue; + } + + let store; + if (line.charAt(0) == '!') { + store = exceptions; + line = line.slice(1); + } else { + store = rules; + } + + if (reMustPunycode.test(line)) { + line = toAscii(line); + } + + line = line.toLowerCase(); + + let tld; + pos = line.lastIndexOf('.'); + if (pos < 0) { + tld = line; + } else { + tld = line.slice(pos+1); + line = line.slice(0, pos); + } + + if (!store.hasOwnProperty(tld)) { + store[tld] = []; + } + + if (line) { + store[tld].push(line); + } } crystallize(exceptions); @@ -245,16 +245,16 @@ function parse(text, toAscii) { function toSelfie() { return { - magic: magic, - rules: rules, - exceptions: exception, + magic: magic, + rules: rules, + exceptions: exception, }; } function fromSelfie(selfie) { if (typeof selfie !== 'object' || typeof selfie.magic !== 'string' - || selfie.magic !== magic) { - return false; + || selfie.magic !== magic) { + return false; } rules = selfie.rules; @@ -266,33 +266,33 @@ function fromSelfie(selfie) { var addListener = function (listeners, callback) { if (typeof callback !== 'function') { - return; + return; } if (listeners.indexOf(callback) === -1) { - listeners.push(callback); + listeners.push(callback); } }; var removeListener = function (listeners, callback) { let pos = listeners.indexOf(callback); if (pos !== -1) { - listeners.splice(pos, 1); + listeners.splice(pos, 1); } }; var callListeners = function (listeners) { for (let i=0; i<listeners.length; ++i) { - listeners[i](); + listeners[i](); } }; var onChanged = { addListener: function (callback) { - addListener(onChangedListeners, callback); + addListener(onChangedListeners, callback); }, removeListener: function (callback) { - removeListener(onChangedListeners, callback); + removeListener(onChangedListeners, callback); }, }; diff --git a/lib/Punycode.jsm b/lib/Punycode.jsm index 0927b87..b601903 100644 --- a/lib/Punycode.jsm +++ b/lib/Punycode.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 Raymond Hill - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2020-2021 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -44,8 +44,8 @@ function mapDomain(domain, cb) { let res = ''; if (parts.length > 1) { - res = parts[0] + '@'; - domain = parts[1]; + res = parts[0] + '@'; + domain = parts[1]; } domain = domain.replace(reSeparator, '\x2E'); @@ -62,22 +62,22 @@ function ucs2decode(str) { let len = str.length; while (count < len) { - let val = str.charCodeAt(count); - ++count; - - if (val >= 0xD800 && val <= 0xDBFF && cound < len) { - let extra = str.charCodeAt(count); - ++count; - - if ((extra & 0xFC00) == 0xDC00) { - res.push(((val & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); - } else { - res.push(val); - --count; - } - } else { - res.push(val); - } + let val = str.charCodeAt(count); + ++count; + + if (val >= 0xD800 && val <= 0xDBFF && cound < len) { + let extra = str.charCodeAt(count); + ++count; + + if ((extra & 0xFC00) == 0xDC00) { + res.push(((val & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); + } else { + res.push(val); + --count; + } + } else { + res.push(val); + } } return res; @@ -85,29 +85,29 @@ function ucs2decode(str) { function ucs2encode(array) { return array.map(function (e) { - let res = ''; + let res = ''; - if (e > 0xFFFF) { - e -= 0x10000; - res += String.fromCharCode(e >>> 10 & 0x3FF | 0xD800); - e = 0xDC00 | e & 0x3FF; - } + if (e > 0xFFFF) { + e -= 0x10000; + res += String.fromCharCode(e >>> 10 & 0x3FF | 0xD800); + e = 0xDC00 | e & 0x3FF; + } - res += String.fromCharCode(e); + res += String.fromCharCode(e); - return res; + return res; }).join(''); } function basicToDigit(point) { if (point - 0x30 < 0x0A) { - return point - 0x16; + return point - 0x16; } if (point - 0x41 < 0x1A) { - return point - 0x41; + return point - 0x41; } if (point - 0x61 < 0x1A) { - return point - 0x61; + return point - 0x61; } return base; } @@ -122,7 +122,7 @@ function adapt(delta, num, first) { delta += Math.floor(delta/num); for (; delta>(base - tMin) * tMax >> 1; k+=base) { - delta = Math.floor(delta/(base-tMin)); + delta = Math.floor(delta/(base-tMin)); } return Math.floor(k + (base - tMin + 1) * delta / (delta + skew)); @@ -137,64 +137,64 @@ function decode(input) { let basic = input.lastIndexOf('-'); if (basic < 0) { - basic = 0; + basic = 0; } for (let j=0; j<basic; ++j) { - if (input.charCodeAt(j) >= 0x80) { - throw new Error('not basic code point'); - } + if (input.charCodeAt(j) >= 0x80) { + throw new Error('not basic code point'); + } - res.push(input.charCodeAt(j)); + res.push(input.charCodeAt(j)); } for (let k=(basic > 0) ? basic + 1 : 0; k<len;) { - let old = i; - let t = 0 + let old = i; + let t = 0 - for (let w=1, x=base; ; x+=base) { - if (k >= len) { - throw new Error('invalid input'); - } + for (let w=1, x=base; ; x+=base) { + if (k >= len) { + throw new Error('invalid input'); + } - let digit = basicToDigit(input.charCodeAt(k)); - ++k; + let digit = basicToDigit(input.charCodeAt(k)); + ++k; - if (digit >= base || digit > Math.floor((maxInt-i) / w)) { - throw new Error('overflow'); - } + if (digit >= base || digit > Math.floor((maxInt-i) / w)) { + throw new Error('overflow'); + } - i += digit * w; + i += digit * w; - t = x <= bias ? - tMin : - (x >= bias + tMax ? - tMax : - x - bias); + t = x <= bias ? + tMin : + (x >= bias + tMax ? + tMax : + x - bias); - if (digit < t) { - break; - } + if (digit < t) { + break; + } - if (w > Math.floor(maxInt/(base - t))) { - throw new Error('overflow'); - } + if (w > Math.floor(maxInt/(base - t))) { + throw new Error('overflow'); + } - w *= (base -t); - } + w *= (base -t); + } - let out = res.length+1; - bias = adapt(i-old, out, old==0); + let out = res.length+1; + bias = adapt(i-old, out, old==0); - if (Math.floor(i/out) > maxInt-n) { - throw new Error('overflow'); - } + if (Math.floor(i/out) > maxInt-n) { + throw new Error('overflow'); + } - n += Math.floor(i/out); - i %= out; + n += Math.floor(i/out); + i %= out; - res.splice(i, 0, n); - ++i; + res.splice(i, 0, n); + ++i; } return ucs2encode(res); @@ -212,71 +212,71 @@ function encode(input) { let bias = 72; for (let j=0; j<len; ++j) { - let val = input[j]; - if (val < 0x80) { - res.push(String.fromCharCode(val)); - } + let val = input[j]; + if (val < 0x80) { + res.push(String.fromCharCode(val)); + } } let blen = res.length; let count = blen; if (blen) { - res.push('-'); + res.push('-'); } while (count < len) { - let m = maxInt; - for (let j=0; j<len; ++j) { - let val = input[j]; - if (val >= n && val <= m) { - m = val; - } - } - - if (m - n > Math.floor((maxInt - delta)/(count+1))) { - throw new Error('overflow'); - } - - delta += (m - n) * (count + 1); - n = m; - - for (let j=0; j<len; ++j) { - let val = input[j]; - - if (val < n && ++delta > maxInt) { - throw new Error('overflow'); - } - - if (val == n) { - let q = delta; - for (let k=base; ; k+=base) { - let t = k <= bias ? - tMin : - (k >= bias + tMax ? - tMax: - k - bias); - - if (q < t) { - break; - } - - res.push - (String.fromCharCode - (digitToBasic(t + (q-t) % (base-t), 0))); - - q = Math.floor((q-t)/(base-t)); - } - - res.push(String.fromCharCode(digitToBasic(q, 0))); - bias = adapt(delta, count+1, count==blen); - delta = 0; - ++count; - } - } - - ++delta; - ++n; + let m = maxInt; + for (let j=0; j<len; ++j) { + let val = input[j]; + if (val >= n && val <= m) { + m = val; + } + } + + if (m - n > Math.floor((maxInt - delta)/(count+1))) { + throw new Error('overflow'); + } + + delta += (m - n) * (count + 1); + n = m; + + for (let j=0; j<len; ++j) { + let val = input[j]; + + if (val < n && ++delta > maxInt) { + throw new Error('overflow'); + } + + if (val == n) { + let q = delta; + for (let k=base; ; k+=base) { + let t = k <= bias ? + tMin : + (k >= bias + tMax ? + tMax: + k - bias); + + if (q < t) { + break; + } + + res.push + (String.fromCharCode + (digitToBasic(t + (q-t) % (base-t), 0))); + + q = Math.floor((q-t)/(base-t)); + } + + res.push(String.fromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, count+1, count==blen); + delta = 0; + ++count; + } + } + + ++delta; + ++n; } return res.join(''); @@ -284,20 +284,20 @@ function encode(input) { function toUnicode(input) { return mapDomain(input, function (e) { - return rePuny.test(e) ? decode(e.slice(4).toLowerCase()) : e; + return rePuny.test(e) ? decode(e.slice(4).toLowerCase()) : e; }); } function toASCII(input) { return mapDomain(input, function (e) { - return reNonAscii.test(e) ? 'xn--' + encode(e) : e; + return reNonAscii.test(e) ? 'xn--' + encode(e) : e; }); } var Punycode = { ucs2: { - decode: ucs2decode, - encode: ucs2encode, + decode: ucs2decode, + encode: ucs2encode, }, decode: decode, encode: encode, diff --git a/lib/RowSnapshot.jsm b/lib/RowSnapshot.jsm index 43f20c3..c202183 100644 --- a/lib/RowSnapshot.jsm +++ b/lib/RowSnapshot.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 Raymond Hill - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2020-2021 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/Tools.jsm b/lib/Tools.jsm index c57a5eb..4019aa6 100644 --- a/lib/Tools.jsm +++ b/lib/Tools.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 Raymond Hill - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2020-2021 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -33,34 +33,34 @@ var LineIterator = function (text, offset) { LineIterator.prototype = { next: function () { - let end = this.text.indexOf('\n', this.offset); - if (end === -1) { - end = this.text.indexOf('\r', this.offset); - if (end === -1) { - end = this.textLen; - } - } - - let line = this.text.slice(this.offset, end); - this.offset = end + 1; - - return line; + let end = this.text.indexOf('\n', this.offset); + if (end === -1) { + end = this.text.indexOf('\r', this.offset); + if (end === -1) { + end = this.textLen; + } + } + + let line = this.text.slice(this.offset, end); + this.offset = end + 1; + + return line; }, rewind: function () { - if (this.offset <= 1) { - this.offset = 0; - } - - let end = this.text.lastIndexOf('\n', this.offset - 2); - if (end === -1) { - this.offset = end + 1; - } else { - end = this.text.lastIndexOf('\r', this.offset - 2); - this.offset = end !== -1 ? end + 1 : 0; - } + if (this.offset <= 1) { + this.offset = 0; + } + + let end = this.text.lastIndexOf('\n', this.offset - 2); + if (end === -1) { + this.offset = end + 1; + } else { + end = this.text.lastIndexOf('\r', this.offset - 2); + this.offset = end !== -1 ? end + 1 : 0; + } }, eot: function () { - return this.offset >= this.textLen; + return this.offset >= this.textLen; }, }; @@ -69,15 +69,15 @@ if (typeof Array.from === 'function') { setToArray = Array.from; } else { setToArray = function (set) { - let out = []; - let entries = set.values(); + let out = []; + let entries = set.values(); - for (let entry=entries.next(); - !entry||!entry.done; entry=entries.next()) { - out.push(entry.value); - } + for (let entry=entries.next(); + !entry||!entry.done; entry=entries.next()) { + out.push(entry.value); + } - return out; + return out; }; } @@ -86,33 +86,33 @@ var Tools = { setToArray: setToArray, gotoURL: function (context) { - if (typeof context !== 'object') { - throw new TypeError(context); - } + if (typeof context !== 'object') { + throw new TypeError(context); + } - context.api.tabs.open(context.details); + context.api.tabs.open(context.details); }, gotoExtensionURL: function (context) { - if (typeof context !== 'object') { - throw new TypeError(context); - } - - let details = context.details; - let api = context.api; - let matrix = context.matrix; - - if (details.url.startsWith('logger-ui.html')) { - if (details.shiftKey) { - let setting = matrix.userSettings.alwaysDetachLogger; - matrix.changeUserSettings('alwaysDetachLogger', !setting); - } - details.popup = matrix.userSettings.alwaysDetachLogger; - } - - details.select = true; - api.tabs.open(details); + if (typeof context !== 'object') { + throw new TypeError(context); + } + + let details = context.details; + let api = context.api; + let matrix = context.matrix; + + if (details.url.startsWith('logger-ui.html')) { + if (details.shiftKey) { + let setting = matrix.userSettings.alwaysDetachLogger; + matrix.changeUserSettings('alwaysDetachLogger', !setting); + } + details.popup = matrix.userSettings.alwaysDetachLogger; + } + + details.select = true; + api.tabs.open(details); }, setFromArray: function (a) { - return new Set(a); + return new Set(a); }, }; diff --git a/lib/UriTools.jsm b/lib/UriTools.jsm index 892dc44..1c3fa0d 100644 --- a/lib/UriTools.jsm +++ b/lib/UriTools.jsm @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 Raymond Hill - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -99,9 +99,9 @@ function URI() { this.fragmentBit = (1 << 7), this.allBits = (0xFFFF), this.authorityBit = - (this.userBit | this.passwordBit | this.hostnameBit | this.portBit); + (this.userBit | this.passwordBit | this.hostnameBit | this.portBit); this.normalizeBits = - (this.schemeBit | this.hostnameBit | this.pathBit | this.queryBit); + (this.schemeBit | this.hostnameBit | this.pathBit | this.queryBit); } var cached = new URI(); @@ -125,14 +125,14 @@ DomainCacheEntry.prototype.init = function (domain) { DomainCacheEntry.prototype.dispose = function () { this.domain = ''; if (cacheJunkyard.length < junkyardMax) { - cacheJunkyard.push(this); + cacheJunkyard.push(this); } }; var domainCacheEntryFactory = function (domain) { let entry = cacheJunkyard.pop(); if (entry) { - return entry.init(domain); + return entry.init(domain); } return new DomainCacheEntry(domain); }; @@ -141,12 +141,12 @@ var domainCacheAdd = function (hostname, domain) { let entry = domainCache.get(hostname); if (entry !== undefined) { - entry.tstamp = Date.now(); + entry.tstamp = Date.now(); } else { - domainCache.set(hostname, domainCacheEntryFactory(domain)); - if (domainCache.size === cacheCountHigh) { - domainCachePrune(); - } + domainCache.set(hostname, domainCacheEntryFactory(domain)); + if (domainCache.size === cacheCountHigh) { + domainCachePrune(); + } } return domain; @@ -158,11 +158,11 @@ var domainCacheSort = function (a, b) { var domainCachePrune = function () { let hostnames = - Array.from(domainCache.keys()).sort(domainCacheSort).slice(cacheCountLow); + Array.from(domainCache.keys()).sort(domainCacheSort).slice(cacheCountLow); for (let i=hostnames.length-1; i>=0; --i) { - domainCache.get(hostnames[i]).dispose(); - domainCache.delete(hostnames[i]); + domainCache.get(hostnames[i]).dispose(); + domainCache.delete(hostnames[i]); } }; @@ -174,232 +174,232 @@ publicSuffixList.onChanged.addListener(domainCacheReset); var UriTools = { set: function (uri) { - if (uri === undefined) { - return reset(cached); - } - - let matches = reRFC3986.exec(uri); - if (!matches) { - return reset(cached); - } - - cached.scheme = matches[1] !== undefined ? - matches[1].slice(0, -1) : - ''; - cached.authority = matches[2] !== undefined ? - matches[2].slice(2).toLowerCase() : - ''; - cached.path = matches[3] !== undefined ? - matches[3] : - ''; - - // As per RFC3986 - if (cached.authority !== '' && cached.path === '') { - cached.path = '/'; - } - - cached.query = matches[4] !== undefined ? - matches[4].slice(1) : - ''; - cached.fragment = matches[5] !== undefined ? - matches[5].slice(1) : - ''; - - if (reHostFromNakedAuthority.test(cached.authority)) { - cached.hostname = cached.authority; - cached.port = ''; - return cached; - } - - matches = reHostPortFromAuthority.exec(cached.authority); - if (!matches) { - matches = reIPv6PortFromAuthority.exec(cached.authority); - if (!matches) { - return resetAuthority(cached); - } - } - - cached.hostname = matches[1] !== undefined ? - matches[1] : - ''; - - if (cached.hostname.slice(-1) === '.') { - cached.hostname = cached.hostname.slice(0, -1); - } - - cached.port = matches[2] !== undefined ? - matches[2].slice(1) : - ''; - - return cached; + if (uri === undefined) { + return reset(cached); + } + + let matches = reRFC3986.exec(uri); + if (!matches) { + return reset(cached); + } + + cached.scheme = matches[1] !== undefined ? + matches[1].slice(0, -1) : + ''; + cached.authority = matches[2] !== undefined ? + matches[2].slice(2).toLowerCase() : + ''; + cached.path = matches[3] !== undefined ? + matches[3] : + ''; + + // As per RFC3986 + if (cached.authority !== '' && cached.path === '') { + cached.path = '/'; + } + + cached.query = matches[4] !== undefined ? + matches[4].slice(1) : + ''; + cached.fragment = matches[5] !== undefined ? + matches[5].slice(1) : + ''; + + if (reHostFromNakedAuthority.test(cached.authority)) { + cached.hostname = cached.authority; + cached.port = ''; + return cached; + } + + matches = reHostPortFromAuthority.exec(cached.authority); + if (!matches) { + matches = reIPv6PortFromAuthority.exec(cached.authority); + if (!matches) { + return resetAuthority(cached); + } + } + + cached.hostname = matches[1] !== undefined ? + matches[1] : + ''; + + if (cached.hostname.slice(-1) === '.') { + cached.hostname = cached.hostname.slice(0, -1); + } + + cached.port = matches[2] !== undefined ? + matches[2].slice(1) : + ''; + + return cached; }, assemble: function (bits) { - if (bits === undefined) { - bits = cached.allBits; - } + if (bits === undefined) { + bits = cached.allBits; + } - let s = []; + let s = []; - if (cached.scheme && (bits && cached.schemeBit)) { - s.push(cached.scheme, ':'); - } - if (cached.hostname && (bits & cached.hostnameBit)) { + if (cached.scheme && (bits && cached.schemeBit)) { + s.push(cached.scheme, ':'); + } + if (cached.hostname && (bits & cached.hostnameBit)) { s.push('//', cached.hostname); - } - if (cached.port && (bits & cached.portBit)) { + } + if (cached.port && (bits & cached.portBit)) { s.push(':', cached.port); - } - if (cached.path && (bits & cached.pathBit)) { + } + if (cached.path && (bits & cached.pathBit)) { s.push(cached.path); - } - if (cached.query && (bits & cached.queryBit)) { + } + if (cached.query && (bits & cached.queryBit)) { s.push('?', cached.query); - } - if (cached.fragment && (bits & cached.fragmentBit)) { + } + if (cached.fragment && (bits & cached.fragmentBit)) { s.push('#', cached.fragment); - } + } - return s.join(''); + return s.join(''); }, isNetworkScheme: function (scheme) { - return reNetworkScheme.test(scheme); + return reNetworkScheme.test(scheme); }, isSecureScheme: function(scheme) { - return reSecureScheme.test(scheme); + return reSecureScheme.test(scheme); }, originFromURI: function (uri) { - let matches = reOriginFromURI.exec(uri); - return matches !== null ? matches[0].toLowerCase() : ''; + let matches = reOriginFromURI.exec(uri); + return matches !== null ? matches[0].toLowerCase() : ''; }, schemeFromURI: function (uri) { - let matches = reSchemeFromURI.exec(uri); - return matches !== null ? matches[0].slice(0, -1).toLowerCase() : ''; + let matches = reSchemeFromURI.exec(uri); + return matches !== null ? matches[0].slice(0, -1).toLowerCase() : ''; }, authorityFromURI: function (uri) { - let matches = reAuthorityFromURI.exec(uri); - return matches !== null ? matches[1].slice(1).toLowerCase() : ''; + let matches = reAuthorityFromURI.exec(uri); + return matches !== null ? matches[1].slice(1).toLowerCase() : ''; }, hostnameFromURI: function (uri) { - let matches = reCommonHostnameFromURL.exec(uri); - if (matches) { - return matches[1]; - } - - matches = reAuthorityFromURI.exec(uri); - if (!matches) { - return ''; - } - - let auth = matches[1].slice(2); - - if (reHostFromNakedAuthority.test(auth)) { - return auth.toLowerCase(); - } - - matches = reHostFromAuthority.exec(auth); - if (!matches) { - matches = reIPv6FromAuthority.exec(auth); - if (!matches) { - return ''; - } - } - - let hostname = matches[1]; - while (hostname.endsWith('.')) { - hostname = hostname.slice(0, -1); - } - - if (reMustNormalizeHostname.test(hostname)) { - Punycode.toASCII(hostname.toLowerCase()); - } - - return hostname; + let matches = reCommonHostnameFromURL.exec(uri); + if (matches) { + return matches[1]; + } + + matches = reAuthorityFromURI.exec(uri); + if (!matches) { + return ''; + } + + let auth = matches[1].slice(2); + + if (reHostFromNakedAuthority.test(auth)) { + return auth.toLowerCase(); + } + + matches = reHostFromAuthority.exec(auth); + if (!matches) { + matches = reIPv6FromAuthority.exec(auth); + if (!matches) { + return ''; + } + } + + let hostname = matches[1]; + while (hostname.endsWith('.')) { + hostname = hostname.slice(0, -1); + } + + if (reMustNormalizeHostname.test(hostname)) { + Punycode.toASCII(hostname.toLowerCase()); + } + + return hostname; }, domainFromHostname: function (hostname) { - let entry = domainCache.get(hostname); - if (entry !== undefined) { - entry.tstamp = Date.now(); - return entry.domain; - } - - if (reIPAddressNaive.test(hostname) == false) { - return domainCacheAdd(hostname, - publicSuffixList.getDomain(hostname)); - } - - return domainCacheAdd(hostname, hostname); + let entry = domainCache.get(hostname); + if (entry !== undefined) { + entry.tstamp = Date.now(); + return entry.domain; + } + + if (reIPAddressNaive.test(hostname) == false) { + return domainCacheAdd(hostname, + publicSuffixList.getDomain(hostname)); + } + + return domainCacheAdd(hostname, hostname); }, domainFromURI: function (uri) { - if (!uri) { - return ''; - } - return UriTools.domainFromHostname(UriTools.hostnameFromURI(uri)); + if (!uri) { + return ''; + } + return UriTools.domainFromHostname(UriTools.hostnameFromURI(uri)); }, domain: function() { - return UriTools.domainFromHostname(cached.hostname); + return UriTools.domainFromHostname(cached.hostname); }, pathFromURI: function (uri) { - let matches = rePathFromURI.exec(uri); - return matches !== null ? matches[1] : ''; + let matches = rePathFromURI.exec(uri); + return matches !== null ? matches[1] : ''; }, normalizedURI: function () { - return UriTools.assemble(cached.normalizeBits); + return UriTools.assemble(cached.normalizeBits); }, rootURL: function () { - if (!cached.hostname) { - return ''; - } - return UriTools.assemble(cached.scemeBit | cached.hostnameBit); + if (!cached.hostname) { + return ''; + } + return UriTools.assemble(cached.scemeBit | cached.hostnameBit); }, isValidHostname: function (hostname) { - try { - let r = reValidHostname.test(hostname); - return r; - } catch (e) { - return false; - } + try { + let r = reValidHostname.test(hostname); + return r; + } catch (e) { + return false; + } }, parentHostnameFromHostname: function (hostname) { - // "locahost" => "" - // "example.org" => "example.org" - // "www.example.org" => "example.org" - // "tomato.www.example.org" => "example.org" - let domain = UriTools.domainFromHostname(hostname); + // "locahost" => "" + // "example.org" => "example.org" + // "www.example.org" => "example.org" + // "tomato.www.example.org" => "example.org" + let domain = UriTools.domainFromHostname(hostname); - if (domain === '' || domain === hostname) { - return undefined; - } + if (domain === '' || domain === hostname) { + return undefined; + } - return hostname.slice(hostname.indexOf('.') + 1); + return hostname.slice(hostname.indexOf('.') + 1); }, parentHostnamesFromHostname: function (hostname) { - let domain = UriTools.domainFromHostname(hostname); - if (domain === '' || domain === hostname) { - return []; - } - - let nodes = []; - for (;;) { - let pos = hostname.indexOf('.'); - if (pos < 0) { - break; - } - - hostname = hostname.slice(pos+1); - nodes.push(hostname); - if (hostname === domain) { - break; - } - } - - return nodes; + let domain = UriTools.domainFromHostname(hostname); + if (domain === '' || domain === hostname) { + return []; + } + + let nodes = []; + for (;;) { + let pos = hostname.indexOf('.'); + if (pos < 0) { + break; + } + + hostname = hostname.slice(pos+1); + nodes.push(hostname); + if (hostname === domain) { + break; + } + } + + return nodes; }, allHostNamesFromHostname: function (hostname) { - let nodes = UriTools.parentHostnamesFromHostname(hostname); - nodes.unshift(hostname); - return nodes; + let nodes = UriTools.parentHostnamesFromHostname(hostname); + nodes.unshift(hostname); + return nodes; }, toString: function () { - return UriTools.assemble(); + return UriTools.assemble(); }, }; diff --git a/lib/publicsuffixlist.js b/lib/publicsuffixlist.js index c0625ab..35b67cd 100644 --- a/lib/publicsuffixlist.js +++ b/lib/publicsuffixlist.js @@ -22,9 +22,9 @@ /*! Home: https://github.com/gorhill/publicsuffixlist.js */ /* - This code is mostly dumb: I consider this to be lower-level code, thus - in order to ensure efficiency, the caller is responsible for sanitizing - the inputs. + This code is mostly dumb: I consider this to be lower-level code, thus + in order to ensure efficiency, the caller is responsible for sanitizing + the inputs. */ /******************************************************************************/ @@ -33,336 +33,336 @@ ;(function(root) { - 'use strict'; +'use strict'; - /******************************************************************************/ - - var exceptions = {}; - var rules = {}; - var selfieMagic = 'iscjsfsaolnm'; +/******************************************************************************/ - // This value dictate how the search will be performed: - // < this.cutoffLength = indexOf() - // >= this.cutoffLength = binary search - var cutoffLength = 256; - var mustPunycode = /[^\w.*-]/; +var exceptions = {}; +var rules = {}; +var selfieMagic = 'iscjsfsaolnm'; - var onChangedListeners = []; +// This value dictate how the search will be performed: +// < this.cutoffLength = indexOf() +// >= this.cutoffLength = binary search +var cutoffLength = 256; +var mustPunycode = /[^\w.*-]/; - /******************************************************************************/ +var onChangedListeners = []; - // In the context of this code, a domain is defined as: - // "{label}.{public suffix}". - // A single standalone label is a public suffix as per - // http://publicsuffix.org/list/: - // "If no rules match, the prevailing rule is '*' " - // This means 'localhost' is not deemed a domain by this - // code, since according to the definition above, it would be - // evaluated as a public suffix. The caller is therefore responsible to - // decide how to further interpret such public suffix. - // - // `hostname` must be a valid ascii-based hostname. +/******************************************************************************/ - function getDomain(hostname) { - // A hostname starting with a dot is not a valid hostname. - if ( !hostname || hostname.charAt(0) === '.' ) { - return ''; - } - hostname = hostname.toLowerCase(); - var suffix = getPublicSuffix(hostname); - if ( suffix === hostname ) { - return ''; - } - var pos = hostname.lastIndexOf('.', hostname.lastIndexOf('.', hostname.length - suffix.length) - 1); - if ( pos <= 0 ) { - return hostname; - } - return hostname.slice(pos + 1); +// In the context of this code, a domain is defined as: +// "{label}.{public suffix}". +// A single standalone label is a public suffix as per +// http://publicsuffix.org/list/: +// "If no rules match, the prevailing rule is '*' " +// This means 'localhost' is not deemed a domain by this +// code, since according to the definition above, it would be +// evaluated as a public suffix. The caller is therefore responsible to +// decide how to further interpret such public suffix. +// +// `hostname` must be a valid ascii-based hostname. + +function getDomain(hostname) { + // A hostname starting with a dot is not a valid hostname. + if ( !hostname || hostname.charAt(0) === '.' ) { + return ''; } - - /******************************************************************************/ - - // Return longest public suffix. - // - // `hostname` must be a valid ascii-based string which respect hostname naming. - - function getPublicSuffix(hostname) { - if ( !hostname ) { - return ''; - } - // Since we slice down the hostname with each pass, the first match - // is the longest, so no need to find all the matching rules. - var pos; - while ( true ) { - pos = hostname.indexOf('.'); - if ( pos < 0 ) { - return hostname; - } - if ( search(exceptions, hostname) ) { - return hostname.slice(pos + 1); - } - if ( search(rules, hostname) ) { - return hostname; - } - if ( search(rules, '*' + hostname.slice(pos)) ) { - return hostname; - } - hostname = hostname.slice(pos + 1); - } - // unreachable + hostname = hostname.toLowerCase(); + var suffix = getPublicSuffix(hostname); + if ( suffix === hostname ) { + return ''; + } + var pos = hostname.lastIndexOf('.', hostname.lastIndexOf('.', hostname.length - suffix.length) - 1); + if ( pos <= 0 ) { + return hostname; } + return hostname.slice(pos + 1); +} - /******************************************************************************/ +/******************************************************************************/ - // Look up a specific hostname. +// Return longest public suffix. +// +// `hostname` must be a valid ascii-based string which respect hostname naming. - function search(store, hostname) { - // Extract TLD - var pos = hostname.lastIndexOf('.'); - var tld, remainder; +function getPublicSuffix(hostname) { + if ( !hostname ) { + return ''; + } + // Since we slice down the hostname with each pass, the first match + // is the longest, so no need to find all the matching rules. + var pos; + while ( true ) { + pos = hostname.indexOf('.'); if ( pos < 0 ) { - tld = hostname; - remainder = hostname; - } else { - tld = hostname.slice(pos + 1); - remainder = hostname.slice(0, pos); - } - var substore = store[tld]; - if ( !substore ) { - return false; + return hostname; } - // If substore is a string, use indexOf() - if ( typeof substore === 'string' ) { - return substore.indexOf(' ' + remainder + ' ') >= 0; + if ( search(exceptions, hostname) ) { + return hostname.slice(pos + 1); } - // It is an array: use binary search. - var l = remainder.length; - var haystack = substore[l]; - if ( !haystack ) { - return false; + if ( search(rules, hostname) ) { + return hostname; } - var left = 0; - var right = Math.floor(haystack.length / l + 0.5); - var i, needle; - while ( left < right ) { - i = left + right >> 1; - needle = haystack.substr( l * i, l ); - if ( remainder < needle ) { - right = i; - } else if ( remainder > needle ) { - left = i + 1; - } else { - return true; - } + if ( search(rules, '*' + hostname.slice(pos)) ) { + return hostname; } - return false; + hostname = hostname.slice(pos + 1); } + // unreachable +} - /******************************************************************************/ - - // Parse and set a UTF-8 text-based suffix list. Format is same as found at: - // http://publicsuffix.org/list/ - // - // `toAscii` is a converter from unicode to punycode. Required since the - // Public Suffix List contains unicode characters. - // Suggestion: use <https://github.com/bestiejs/punycode.js> it's quite good. +/******************************************************************************/ - function parse(text, toAscii) { - exceptions = {}; - rules = {}; +// Look up a specific hostname. + +function search(store, hostname) { + // Extract TLD + var pos = hostname.lastIndexOf('.'); + var tld, remainder; + if ( pos < 0 ) { + tld = hostname; + remainder = hostname; + } else { + tld = hostname.slice(pos + 1); + remainder = hostname.slice(0, pos); + } + var substore = store[tld]; + if ( !substore ) { + return false; + } + // If substore is a string, use indexOf() + if ( typeof substore === 'string' ) { + return substore.indexOf(' ' + remainder + ' ') >= 0; + } + // It is an array: use binary search. + var l = remainder.length; + var haystack = substore[l]; + if ( !haystack ) { + return false; + } + var left = 0; + var right = Math.floor(haystack.length / l + 0.5); + var i, needle; + while ( left < right ) { + i = left + right >> 1; + needle = haystack.substr( l * i, l ); + if ( remainder < needle ) { + right = i; + } else if ( remainder > needle ) { + left = i + 1; + } else { + return true; + } + } + return false; +} - var lineBeg = 0, lineEnd; - var textEnd = text.length; - var line, store, pos, tld; +/******************************************************************************/ - while ( lineBeg < textEnd ) { - lineEnd = text.indexOf('\n', lineBeg); +// Parse and set a UTF-8 text-based suffix list. Format is same as found at: +// http://publicsuffix.org/list/ +// +// `toAscii` is a converter from unicode to punycode. Required since the +// Public Suffix List contains unicode characters. +// Suggestion: use <https://github.com/bestiejs/punycode.js> it's quite good. + +function parse(text, toAscii) { + exceptions = {}; + rules = {}; + + var lineBeg = 0, lineEnd; + var textEnd = text.length; + var line, store, pos, tld; + + while ( lineBeg < textEnd ) { + lineEnd = text.indexOf('\n', lineBeg); + if ( lineEnd < 0 ) { + lineEnd = text.indexOf('\r', lineBeg); if ( lineEnd < 0 ) { - lineEnd = text.indexOf('\r', lineBeg); - if ( lineEnd < 0 ) { - lineEnd = textEnd; - } + lineEnd = textEnd; } - line = text.slice(lineBeg, lineEnd).trim(); - lineBeg = lineEnd + 1; + } + line = text.slice(lineBeg, lineEnd).trim(); + lineBeg = lineEnd + 1; - if ( line.length === 0 ) { - continue; - } + if ( line.length === 0 ) { + continue; + } - // Ignore comments - pos = line.indexOf('//'); - if ( pos >= 0 ) { - line = line.slice(0, pos); - } + // Ignore comments + pos = line.indexOf('//'); + if ( pos >= 0 ) { + line = line.slice(0, pos); + } - // Ignore surrounding whitespaces - line = line.trim(); - if ( !line ) { - continue; - } + // Ignore surrounding whitespaces + line = line.trim(); + if ( !line ) { + continue; + } - // Is this an exception rule? - if ( line.charAt(0) === '!' ) { - store = exceptions; - line = line.slice(1); - } else { - store = rules; - } + // Is this an exception rule? + if ( line.charAt(0) === '!' ) { + store = exceptions; + line = line.slice(1); + } else { + store = rules; + } - if ( mustPunycode.test(line) ) { - line = toAscii(line); - } + if ( mustPunycode.test(line) ) { + line = toAscii(line); + } - // http://publicsuffix.org/list/: - // "... all rules must be canonicalized in the normal way - // for hostnames - lower-case, Punycode ..." - line = line.toLowerCase(); - - // Extract TLD - pos = line.lastIndexOf('.'); - if ( pos < 0 ) { - tld = line; - } else { - tld = line.slice(pos + 1); - line = line.slice(0, pos); - } + // http://publicsuffix.org/list/: + // "... all rules must be canonicalized in the normal way + // for hostnames - lower-case, Punycode ..." + line = line.toLowerCase(); - // Store suffix using tld as key - if ( !store.hasOwnProperty(tld) ) { - store[tld] = []; - } - if ( line ) { - store[tld].push(line); - } + // Extract TLD + pos = line.lastIndexOf('.'); + if ( pos < 0 ) { + tld = line; + } else { + tld = line.slice(pos + 1); + line = line.slice(0, pos); } - crystallize(exceptions); - crystallize(rules); - callListeners(onChangedListeners); + // Store suffix using tld as key + if ( !store.hasOwnProperty(tld) ) { + store[tld] = []; + } + if ( line ) { + store[tld].push(line); + } } + crystallize(exceptions); + crystallize(rules); - /******************************************************************************/ + callListeners(onChangedListeners); +} - // Cristallize the storage of suffixes using optimal internal representation - // for future look up. +/******************************************************************************/ - function crystallize(store) { - var suffixes, suffix, i, l; +// Cristallize the storage of suffixes using optimal internal representation +// for future look up. - for ( var tld in store ) { - if ( !store.hasOwnProperty(tld) ) { - continue; - } - suffixes = store[tld].join(' '); - // No suffix - if ( !suffixes ) { - store[tld] = ''; - continue; - } - // Concatenated list of suffixes less than cutoff length: - // Store as string, lookup using indexOf() - if ( suffixes.length < cutoffLength ) { - store[tld] = ' ' + suffixes + ' '; - continue; - } - // Concatenated list of suffixes greater or equal to cutoff length - // Store as array keyed on suffix length, lookup using binary search. - // I borrowed the idea to key on string length here: - // http://ejohn.org/blog/dictionary-lookups-in-javascript/#comment-392072 - - i = store[tld].length; - suffixes = []; - while ( i-- ) { - suffix = store[tld][i]; - l = suffix.length; - if ( !suffixes[l] ) { - suffixes[l] = []; - } - suffixes[l].push(suffix); +function crystallize(store) { + var suffixes, suffix, i, l; + + for ( var tld in store ) { + if ( !store.hasOwnProperty(tld) ) { + continue; + } + suffixes = store[tld].join(' '); + // No suffix + if ( !suffixes ) { + store[tld] = ''; + continue; + } + // Concatenated list of suffixes less than cutoff length: + // Store as string, lookup using indexOf() + if ( suffixes.length < cutoffLength ) { + store[tld] = ' ' + suffixes + ' '; + continue; + } + // Concatenated list of suffixes greater or equal to cutoff length + // Store as array keyed on suffix length, lookup using binary search. + // I borrowed the idea to key on string length here: + // http://ejohn.org/blog/dictionary-lookups-in-javascript/#comment-392072 + + i = store[tld].length; + suffixes = []; + while ( i-- ) { + suffix = store[tld][i]; + l = suffix.length; + if ( !suffixes[l] ) { + suffixes[l] = []; } - l = suffixes.length; - while ( l-- ) { - if ( suffixes[l] ) { - suffixes[l] = suffixes[l].sort().join(''); - } + suffixes[l].push(suffix); + } + l = suffixes.length; + while ( l-- ) { + if ( suffixes[l] ) { + suffixes[l] = suffixes[l].sort().join(''); } - store[tld] = suffixes; } - return store; + store[tld] = suffixes; } + return store; +} - /******************************************************************************/ +/******************************************************************************/ - function toSelfie() { - return { - magic: selfieMagic, - rules: rules, - exceptions: exceptions - }; - } +function toSelfie() { + return { + magic: selfieMagic, + rules: rules, + exceptions: exceptions + }; +} - function fromSelfie(selfie) { - if ( typeof selfie !== 'object' || typeof selfie.magic !== 'string' || selfie.magic !== selfieMagic ) { - return false; - } - rules = selfie.rules; - exceptions = selfie.exceptions; - callListeners(onChangedListeners); - return true; +function fromSelfie(selfie) { + if ( typeof selfie !== 'object' || typeof selfie.magic !== 'string' || selfie.magic !== selfieMagic ) { + return false; } + rules = selfie.rules; + exceptions = selfie.exceptions; + callListeners(onChangedListeners); + return true; +} - /******************************************************************************/ +/******************************************************************************/ - var addListener = function(listeners, callback) { - if ( typeof callback !== 'function' ) { - return; - } - if ( listeners.indexOf(callback) === -1 ) { - listeners.push(callback); - } - }; +var addListener = function(listeners, callback) { + if ( typeof callback !== 'function' ) { + return; + } + if ( listeners.indexOf(callback) === -1 ) { + listeners.push(callback); + } +}; - var removeListener = function(listeners, callback) { - var pos = listeners.indexOf(callback); - if ( pos !== -1 ) { - listeners.splice(pos, 1); - } - }; +var removeListener = function(listeners, callback) { + var pos = listeners.indexOf(callback); + if ( pos !== -1 ) { + listeners.splice(pos, 1); + } +}; - var callListeners = function(listeners) { - for ( var i = 0; i < listeners.length; i++ ) { - listeners[i](); - } - }; +var callListeners = function(listeners) { + for ( var i = 0; i < listeners.length; i++ ) { + listeners[i](); + } +}; - /******************************************************************************/ +/******************************************************************************/ - var onChanged = { - addListener: function(callback) { - addListener(onChangedListeners, callback); - }, - removeListener: function(callback) { - removeListener(onChangedListeners, callback); - } - }; +var onChanged = { + addListener: function(callback) { + addListener(onChangedListeners, callback); + }, + removeListener: function(callback) { + removeListener(onChangedListeners, callback); + } +}; - /******************************************************************************/ +/******************************************************************************/ - // Public API +// Public API - root = root || window; +root = root || window; - root.publicSuffixList = { - 'version': '1.0', - 'parse': parse, - 'getDomain': getDomain, - 'getPublicSuffix': getPublicSuffix, - 'toSelfie': toSelfie, - 'fromSelfie': fromSelfie, - 'onChanged': onChanged - }; +root.publicSuffixList = { + 'version': '1.0', + 'parse': parse, + 'getDomain': getDomain, + 'getPublicSuffix': getPublicSuffix, + 'toSelfie': toSelfie, + 'fromSelfie': fromSelfie, + 'onChanged': onChanged +}; - /******************************************************************************/ +/******************************************************************************/ })(this); diff --git a/lib/punycode.js b/lib/punycode.js index b66096e..c965f8b 100644 --- a/lib/punycode.js +++ b/lib/punycode.js @@ -23,530 +23,530 @@ /*! https://mths.be/punycode v1.3.2 by @mathias */ ;(function(root) { - /** Detect free variables */ - var freeExports = typeof exports == 'object' && exports && - !exports.nodeType && exports; - var freeModule = typeof module == 'object' && module && - !module.nodeType && module; - var freeGlobal = typeof global == 'object' && global; - if ( - freeGlobal.global === freeGlobal || - freeGlobal.window === freeGlobal || - freeGlobal.self === freeGlobal - ) { - root = freeGlobal; - } - - /** - * The `punycode` object. - * @name punycode - * @type Object - */ - var punycode, - - /** Highest positive signed 32-bit float value */ - maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 - - /** Bootstring parameters */ - base = 36, - tMin = 1, - tMax = 26, - skew = 38, - damp = 700, - initialBias = 72, - initialN = 128, // 0x80 - delimiter = '-', // '\x2D' - - /** Regular expressions */ - regexPunycode = /^xn--/, - regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars - regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators - - /** Error messages */ - errors = { - 'overflow': 'Overflow: input needs wider integers to process', - 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', - 'invalid-input': 'Invalid input' - }, - - /** Convenience shortcuts */ - baseMinusTMin = base - tMin, - floor = Math.floor, - stringFromCharCode = String.fromCharCode, - - /** Temporary variable */ - key; - - /*--------------------------------------------------------------------------*/ - - /** - * A generic error utility function. - * @private - * @param {String} type The error type. - * @returns {Error} Throws a `RangeError` with the applicable error message. - */ - function error(type) { - throw RangeError(errors[type]); - } - - /** - * A generic `Array#map` utility function. - * @private - * @param {Array} array The array to iterate over. - * @param {Function} callback The function that gets called for every array - * item. - * @returns {Array} A new array of values returned by the callback function. - */ - function map(array, fn) { - var length = array.length; - var result = []; - while (length--) { - result[length] = fn(array[length]); - } - return result; - } - - /** - * A simple `Array#map`-like wrapper to work with domain name strings or email - * addresses. - * @private - * @param {String} domain The domain name or email address. - * @param {Function} callback The function that gets called for every - * character. - * @returns {Array} A new string of characters returned by the callback - * function. - */ - function mapDomain(string, fn) { - var parts = string.split('@'); - var result = ''; - if (parts.length > 1) { - // In email addresses, only the domain name should be punycoded. Leave - // the local part (i.e. everything up to `@`) intact. - result = parts[0] + '@'; - string = parts[1]; - } - // Avoid `split(regex)` for IE8 compatibility. See #17. - string = string.replace(regexSeparators, '\x2E'); - var labels = string.split('.'); - var encoded = map(labels, fn).join('.'); - return result + encoded; - } - - /** - * Creates an array containing the numeric code points of each Unicode - * character in the string. While JavaScript uses UCS-2 internally, - * this function will convert a pair of surrogate halves (each of which - * UCS-2 exposes as separate characters) into a single code point, - * matching UTF-16. - * @see `punycode.ucs2.encode` - * @see <https://mathiasbynens.be/notes/javascript-encoding> - * @memberOf punycode.ucs2 - * @name decode - * @param {String} string The Unicode input string (UCS-2). - * @returns {Array} The new array of code points. - */ - function ucs2decode(string) { - var output = [], - counter = 0, - length = string.length, - value, - extra; - while (counter < length) { - value = string.charCodeAt(counter++); - if (value >= 0xD800 && value <= 0xDBFF && counter < length) { - // high surrogate, and there is a next character - extra = string.charCodeAt(counter++); - if ((extra & 0xFC00) == 0xDC00) { // low surrogate - output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); - } else { - // unmatched surrogate; only append this code unit, in case the next - // code unit is the high surrogate of a surrogate pair - output.push(value); - counter--; - } - } else { - output.push(value); - } - } - return output; - } - - /** - * Creates a string based on an array of numeric code points. - * @see `punycode.ucs2.decode` - * @memberOf punycode.ucs2 - * @name encode - * @param {Array} codePoints The array of numeric code points. - * @returns {String} The new Unicode string (UCS-2). - */ - function ucs2encode(array) { - return map(array, function(value) { - var output = ''; - if (value > 0xFFFF) { - value -= 0x10000; - output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); - value = 0xDC00 | value & 0x3FF; - } - output += stringFromCharCode(value); - return output; - }).join(''); - } - - /** - * Converts a basic code point into a digit/integer. - * @see `digitToBasic()` - * @private - * @param {Number} codePoint The basic numeric code point value. - * @returns {Number} The numeric value of a basic code point (for use in - * representing integers) in the range `0` to `base - 1`, or `base` if - * the code point does not represent a value. - */ - function basicToDigit(codePoint) { - if (codePoint - 48 < 10) { - return codePoint - 22; - } - if (codePoint - 65 < 26) { - return codePoint - 65; - } - if (codePoint - 97 < 26) { - return codePoint - 97; - } - return base; - } - - /** - * Converts a digit/integer into a basic code point. - * @see `basicToDigit()` - * @private - * @param {Number} digit The numeric value of a basic code point. - * @returns {Number} The basic code point whose value (when used for - * representing integers) is `digit`, which needs to be in the range - * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is - * used; else, the lowercase form is used. The behavior is undefined - * if `flag` is non-zero and `digit` has no uppercase form. - */ - function digitToBasic(digit, flag) { - // 0..25 map to ASCII a..z or A..Z - // 26..35 map to ASCII 0..9 - return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); - } - - /** - * Bias adaptation function as per section 3.4 of RFC 3492. - * http://tools.ietf.org/html/rfc3492#section-3.4 - * @private - */ - function adapt(delta, numPoints, firstTime) { - var k = 0; - delta = firstTime ? floor(delta / damp) : delta >> 1; - delta += floor(delta / numPoints); - for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { - delta = floor(delta / baseMinusTMin); - } - return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); - } - - /** - * Converts a Punycode string of ASCII-only symbols to a string of Unicode - * symbols. - * @memberOf punycode - * @param {String} input The Punycode string of ASCII-only symbols. - * @returns {String} The resulting string of Unicode symbols. - */ - function decode(input) { - // Don't use UCS-2 - var output = [], - inputLength = input.length, - out, - i = 0, - n = initialN, - bias = initialBias, - basic, - j, - index, - oldi, - w, - k, - digit, - t, - /** Cached calculation results */ - baseMinusT; - - // Handle the basic code points: let `basic` be the number of input code - // points before the last delimiter, or `0` if there is none, then copy - // the first basic code points to the output. - - basic = input.lastIndexOf(delimiter); - if (basic < 0) { - basic = 0; - } - - for (j = 0; j < basic; ++j) { - // if it's not a basic code point - if (input.charCodeAt(j) >= 0x80) { - error('not-basic'); - } - output.push(input.charCodeAt(j)); - } - - // Main decoding loop: start just after the last delimiter if any basic code - // points were copied; start at the beginning otherwise. - - for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { - - // `index` is the index of the next character to be consumed. - // Decode a generalized variable-length integer into `delta`, - // which gets added to `i`. The overflow checking is easier - // if we increase `i` as we go, then subtract off its starting - // value at the end to obtain `delta`. - for (oldi = i, w = 1, k = base; /* no condition */; k += base) { - - if (index >= inputLength) { - error('invalid-input'); - } - - digit = basicToDigit(input.charCodeAt(index++)); - - if (digit >= base || digit > floor((maxInt - i) / w)) { - error('overflow'); - } - - i += digit * w; - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - - if (digit < t) { - break; - } - - baseMinusT = base - t; - if (w > floor(maxInt / baseMinusT)) { - error('overflow'); - } - - w *= baseMinusT; - - } - - out = output.length + 1; - bias = adapt(i - oldi, out, oldi == 0); - - // `i` was supposed to wrap around from `out` to `0`, - // incrementing `n` each time, so we'll fix that now: - if (floor(i / out) > maxInt - n) { - error('overflow'); - } - - n += floor(i / out); - i %= out; - - // Insert `n` at position `i` of the output - output.splice(i++, 0, n); - - } - - return ucs2encode(output); - } - - /** - * Converts a string of Unicode symbols (e.g. a domain name label) to a - * Punycode string of ASCII-only symbols. - * @memberOf punycode - * @param {String} input The string of Unicode symbols. - * @returns {String} The resulting Punycode string of ASCII-only symbols. - */ - function encode(input) { - var n, - delta, - handledCPCount, - basicLength, - bias, - j, - m, - q, - k, - t, - currentValue, - output = [], - /** `inputLength` will hold the number of code points in `input`. */ - inputLength, - /** Cached calculation results */ - handledCPCountPlusOne, - baseMinusT, - qMinusT; - - // Convert the input in UCS-2 to Unicode - input = ucs2decode(input); - - // Cache the length - inputLength = input.length; - - // Initialize the state - n = initialN; - delta = 0; - bias = initialBias; - - // Handle the basic code points - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue < 0x80) { - output.push(stringFromCharCode(currentValue)); - } - } - - handledCPCount = basicLength = output.length; - - // `handledCPCount` is the number of code points that have been handled; - // `basicLength` is the number of basic code points. - - // Finish the basic string - if it is not empty - with a delimiter - if (basicLength) { - output.push(delimiter); - } - - // Main encoding loop: - while (handledCPCount < inputLength) { - - // All non-basic code points < n have been handled already. Find the next - // larger one: - for (m = maxInt, j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue >= n && currentValue < m) { - m = currentValue; - } - } - - // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, - // but guard against overflow - handledCPCountPlusOne = handledCPCount + 1; - if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { - error('overflow'); - } - - delta += (m - n) * handledCPCountPlusOne; - n = m; - - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - - if (currentValue < n && ++delta > maxInt) { - error('overflow'); - } - - if (currentValue == n) { - // Represent delta as a generalized variable-length integer - for (q = delta, k = base; /* no condition */; k += base) { - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - if (q < t) { - break; - } - qMinusT = q - t; - baseMinusT = base - t; - output.push( - stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) - ); - q = floor(qMinusT / baseMinusT); - } - - output.push(stringFromCharCode(digitToBasic(q, 0))); - bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); - delta = 0; - ++handledCPCount; - } - } - - ++delta; - ++n; - - } - return output.join(''); - } - - /** - * Converts a Punycode string representing a domain name or an email address - * to Unicode. Only the Punycoded parts of the input will be converted, i.e. - * it doesn't matter if you call it on a string that has already been - * converted to Unicode. - * @memberOf punycode - * @param {String} input The Punycoded domain name or email address to - * convert to Unicode. - * @returns {String} The Unicode representation of the given Punycode - * string. - */ - function toUnicode(input) { - return mapDomain(input, function(string) { - return regexPunycode.test(string) - ? decode(string.slice(4).toLowerCase()) - : string; - }); - } - - /** - * Converts a Unicode string representing a domain name or an email address to - * Punycode. Only the non-ASCII parts of the domain name will be converted, - * i.e. it doesn't matter if you call it with a domain that's already in - * ASCII. - * @memberOf punycode - * @param {String} input The domain name or email address to convert, as a - * Unicode string. - * @returns {String} The Punycode representation of the given domain name or - * email address. - */ - function toASCII(input) { - return mapDomain(input, function(string) { - return regexNonASCII.test(string) - ? 'xn--' + encode(string) - : string; - }); - } - - /*--------------------------------------------------------------------------*/ - - /** Define the public API */ - punycode = { - /** - * A string representing the current Punycode.js version number. - * @memberOf punycode - * @type String - */ - 'version': '1.3.2', - /** - * An object of methods to convert from JavaScript's internal character - * representation (UCS-2) to Unicode code points, and back. - * @see <https://mathiasbynens.be/notes/javascript-encoding> - * @memberOf punycode - * @type Object - */ - 'ucs2': { - 'decode': ucs2decode, - 'encode': ucs2encode - }, - 'decode': decode, - 'encode': encode, - 'toASCII': toASCII, - 'toUnicode': toUnicode - }; - - /** Expose `punycode` */ - // Some AMD build optimizers, like r.js, check for specific condition patterns - // like the following: - if ( - typeof define == 'function' && - typeof define.amd == 'object' && - define.amd - ) { - define('punycode', function() { - return punycode; - }); - } else if (freeExports && freeModule) { - if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+ - freeModule.exports = punycode; - } else { // in Narwhal or RingoJS v0.7.0- - for (key in punycode) { - punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); - } - } - } else { // in Rhino or a web browser - root.punycode = punycode; - } + /** Detect free variables */ + var freeExports = typeof exports == 'object' && exports && + !exports.nodeType && exports; + var freeModule = typeof module == 'object' && module && + !module.nodeType && module; + var freeGlobal = typeof global == 'object' && global; + if ( + freeGlobal.global === freeGlobal || + freeGlobal.window === freeGlobal || + freeGlobal.self === freeGlobal + ) { + root = freeGlobal; + } + + /** + * The `punycode` object. + * @name punycode + * @type Object + */ + var punycode, + + /** Highest positive signed 32-bit float value */ + maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 + + /** Bootstring parameters */ + base = 36, + tMin = 1, + tMax = 26, + skew = 38, + damp = 700, + initialBias = 72, + initialN = 128, // 0x80 + delimiter = '-', // '\x2D' + + /** Regular expressions */ + regexPunycode = /^xn--/, + regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars + regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators + + /** Error messages */ + errors = { + 'overflow': 'Overflow: input needs wider integers to process', + 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', + 'invalid-input': 'Invalid input' + }, + + /** Convenience shortcuts */ + baseMinusTMin = base - tMin, + floor = Math.floor, + stringFromCharCode = String.fromCharCode, + + /** Temporary variable */ + key; + + /*--------------------------------------------------------------------------*/ + + /** + * A generic error utility function. + * @private + * @param {String} type The error type. + * @returns {Error} Throws a `RangeError` with the applicable error message. + */ + function error(type) { + throw RangeError(errors[type]); + } + + /** + * A generic `Array#map` utility function. + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function that gets called for every array + * item. + * @returns {Array} A new array of values returned by the callback function. + */ + function map(array, fn) { + var length = array.length; + var result = []; + while (length--) { + result[length] = fn(array[length]); + } + return result; + } + + /** + * A simple `Array#map`-like wrapper to work with domain name strings or email + * addresses. + * @private + * @param {String} domain The domain name or email address. + * @param {Function} callback The function that gets called for every + * character. + * @returns {Array} A new string of characters returned by the callback + * function. + */ + function mapDomain(string, fn) { + var parts = string.split('@'); + var result = ''; + if (parts.length > 1) { + // In email addresses, only the domain name should be punycoded. Leave + // the local part (i.e. everything up to `@`) intact. + result = parts[0] + '@'; + string = parts[1]; + } + // Avoid `split(regex)` for IE8 compatibility. See #17. + string = string.replace(regexSeparators, '\x2E'); + var labels = string.split('.'); + var encoded = map(labels, fn).join('.'); + return result + encoded; + } + + /** + * Creates an array containing the numeric code points of each Unicode + * character in the string. While JavaScript uses UCS-2 internally, + * this function will convert a pair of surrogate halves (each of which + * UCS-2 exposes as separate characters) into a single code point, + * matching UTF-16. + * @see `punycode.ucs2.encode` + * @see <https://mathiasbynens.be/notes/javascript-encoding> + * @memberOf punycode.ucs2 + * @name decode + * @param {String} string The Unicode input string (UCS-2). + * @returns {Array} The new array of code points. + */ + function ucs2decode(string) { + var output = [], + counter = 0, + length = string.length, + value, + extra; + while (counter < length) { + value = string.charCodeAt(counter++); + if (value >= 0xD800 && value <= 0xDBFF && counter < length) { + // high surrogate, and there is a next character + extra = string.charCodeAt(counter++); + if ((extra & 0xFC00) == 0xDC00) { // low surrogate + output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); + } else { + // unmatched surrogate; only append this code unit, in case the next + // code unit is the high surrogate of a surrogate pair + output.push(value); + counter--; + } + } else { + output.push(value); + } + } + return output; + } + + /** + * Creates a string based on an array of numeric code points. + * @see `punycode.ucs2.decode` + * @memberOf punycode.ucs2 + * @name encode + * @param {Array} codePoints The array of numeric code points. + * @returns {String} The new Unicode string (UCS-2). + */ + function ucs2encode(array) { + return map(array, function(value) { + var output = ''; + if (value > 0xFFFF) { + value -= 0x10000; + output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); + value = 0xDC00 | value & 0x3FF; + } + output += stringFromCharCode(value); + return output; + }).join(''); + } + + /** + * Converts a basic code point into a digit/integer. + * @see `digitToBasic()` + * @private + * @param {Number} codePoint The basic numeric code point value. + * @returns {Number} The numeric value of a basic code point (for use in + * representing integers) in the range `0` to `base - 1`, or `base` if + * the code point does not represent a value. + */ + function basicToDigit(codePoint) { + if (codePoint - 48 < 10) { + return codePoint - 22; + } + if (codePoint - 65 < 26) { + return codePoint - 65; + } + if (codePoint - 97 < 26) { + return codePoint - 97; + } + return base; + } + + /** + * Converts a digit/integer into a basic code point. + * @see `basicToDigit()` + * @private + * @param {Number} digit The numeric value of a basic code point. + * @returns {Number} The basic code point whose value (when used for + * representing integers) is `digit`, which needs to be in the range + * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is + * used; else, the lowercase form is used. The behavior is undefined + * if `flag` is non-zero and `digit` has no uppercase form. + */ + function digitToBasic(digit, flag) { + // 0..25 map to ASCII a..z or A..Z + // 26..35 map to ASCII 0..9 + return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); + } + + /** + * Bias adaptation function as per section 3.4 of RFC 3492. + * http://tools.ietf.org/html/rfc3492#section-3.4 + * @private + */ + function adapt(delta, numPoints, firstTime) { + var k = 0; + delta = firstTime ? floor(delta / damp) : delta >> 1; + delta += floor(delta / numPoints); + for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { + delta = floor(delta / baseMinusTMin); + } + return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); + } + + /** + * Converts a Punycode string of ASCII-only symbols to a string of Unicode + * symbols. + * @memberOf punycode + * @param {String} input The Punycode string of ASCII-only symbols. + * @returns {String} The resulting string of Unicode symbols. + */ + function decode(input) { + // Don't use UCS-2 + var output = [], + inputLength = input.length, + out, + i = 0, + n = initialN, + bias = initialBias, + basic, + j, + index, + oldi, + w, + k, + digit, + t, + /** Cached calculation results */ + baseMinusT; + + // Handle the basic code points: let `basic` be the number of input code + // points before the last delimiter, or `0` if there is none, then copy + // the first basic code points to the output. + + basic = input.lastIndexOf(delimiter); + if (basic < 0) { + basic = 0; + } + + for (j = 0; j < basic; ++j) { + // if it's not a basic code point + if (input.charCodeAt(j) >= 0x80) { + error('not-basic'); + } + output.push(input.charCodeAt(j)); + } + + // Main decoding loop: start just after the last delimiter if any basic code + // points were copied; start at the beginning otherwise. + + for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { + + // `index` is the index of the next character to be consumed. + // Decode a generalized variable-length integer into `delta`, + // which gets added to `i`. The overflow checking is easier + // if we increase `i` as we go, then subtract off its starting + // value at the end to obtain `delta`. + for (oldi = i, w = 1, k = base; /* no condition */; k += base) { + + if (index >= inputLength) { + error('invalid-input'); + } + + digit = basicToDigit(input.charCodeAt(index++)); + + if (digit >= base || digit > floor((maxInt - i) / w)) { + error('overflow'); + } + + i += digit * w; + t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + + if (digit < t) { + break; + } + + baseMinusT = base - t; + if (w > floor(maxInt / baseMinusT)) { + error('overflow'); + } + + w *= baseMinusT; + + } + + out = output.length + 1; + bias = adapt(i - oldi, out, oldi == 0); + + // `i` was supposed to wrap around from `out` to `0`, + // incrementing `n` each time, so we'll fix that now: + if (floor(i / out) > maxInt - n) { + error('overflow'); + } + + n += floor(i / out); + i %= out; + + // Insert `n` at position `i` of the output + output.splice(i++, 0, n); + + } + + return ucs2encode(output); + } + + /** + * Converts a string of Unicode symbols (e.g. a domain name label) to a + * Punycode string of ASCII-only symbols. + * @memberOf punycode + * @param {String} input The string of Unicode symbols. + * @returns {String} The resulting Punycode string of ASCII-only symbols. + */ + function encode(input) { + var n, + delta, + handledCPCount, + basicLength, + bias, + j, + m, + q, + k, + t, + currentValue, + output = [], + /** `inputLength` will hold the number of code points in `input`. */ + inputLength, + /** Cached calculation results */ + handledCPCountPlusOne, + baseMinusT, + qMinusT; + + // Convert the input in UCS-2 to Unicode + input = ucs2decode(input); + + // Cache the length + inputLength = input.length; + + // Initialize the state + n = initialN; + delta = 0; + bias = initialBias; + + // Handle the basic code points + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + if (currentValue < 0x80) { + output.push(stringFromCharCode(currentValue)); + } + } + + handledCPCount = basicLength = output.length; + + // `handledCPCount` is the number of code points that have been handled; + // `basicLength` is the number of basic code points. + + // Finish the basic string - if it is not empty - with a delimiter + if (basicLength) { + output.push(delimiter); + } + + // Main encoding loop: + while (handledCPCount < inputLength) { + + // All non-basic code points < n have been handled already. Find the next + // larger one: + for (m = maxInt, j = 0; j < inputLength; ++j) { + currentValue = input[j]; + if (currentValue >= n && currentValue < m) { + m = currentValue; + } + } + + // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, + // but guard against overflow + handledCPCountPlusOne = handledCPCount + 1; + if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { + error('overflow'); + } + + delta += (m - n) * handledCPCountPlusOne; + n = m; + + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + + if (currentValue < n && ++delta > maxInt) { + error('overflow'); + } + + if (currentValue == n) { + // Represent delta as a generalized variable-length integer + for (q = delta, k = base; /* no condition */; k += base) { + t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + if (q < t) { + break; + } + qMinusT = q - t; + baseMinusT = base - t; + output.push( + stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) + ); + q = floor(qMinusT / baseMinusT); + } + + output.push(stringFromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); + delta = 0; + ++handledCPCount; + } + } + + ++delta; + ++n; + + } + return output.join(''); + } + + /** + * Converts a Punycode string representing a domain name or an email address + * to Unicode. Only the Punycoded parts of the input will be converted, i.e. + * it doesn't matter if you call it on a string that has already been + * converted to Unicode. + * @memberOf punycode + * @param {String} input The Punycoded domain name or email address to + * convert to Unicode. + * @returns {String} The Unicode representation of the given Punycode + * string. + */ + function toUnicode(input) { + return mapDomain(input, function(string) { + return regexPunycode.test(string) + ? decode(string.slice(4).toLowerCase()) + : string; + }); + } + + /** + * Converts a Unicode string representing a domain name or an email address to + * Punycode. Only the non-ASCII parts of the domain name will be converted, + * i.e. it doesn't matter if you call it with a domain that's already in + * ASCII. + * @memberOf punycode + * @param {String} input The domain name or email address to convert, as a + * Unicode string. + * @returns {String} The Punycode representation of the given domain name or + * email address. + */ + function toASCII(input) { + return mapDomain(input, function(string) { + return regexNonASCII.test(string) + ? 'xn--' + encode(string) + : string; + }); + } + + /*--------------------------------------------------------------------------*/ + + /** Define the public API */ + punycode = { + /** + * A string representing the current Punycode.js version number. + * @memberOf punycode + * @type String + */ + 'version': '1.3.2', + /** + * An object of methods to convert from JavaScript's internal character + * representation (UCS-2) to Unicode code points, and back. + * @see <https://mathiasbynens.be/notes/javascript-encoding> + * @memberOf punycode + * @type Object + */ + 'ucs2': { + 'decode': ucs2decode, + 'encode': ucs2encode + }, + 'decode': decode, + 'encode': encode, + 'toASCII': toASCII, + 'toUnicode': toUnicode + }; + + /** Expose `punycode` */ + // Some AMD build optimizers, like r.js, check for specific condition patterns + // like the following: + if ( + typeof define == 'function' && + typeof define.amd == 'object' && + define.amd + ) { + define('punycode', function() { + return punycode; + }); + } else if (freeExports && freeModule) { + if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+ + freeModule.exports = punycode; + } else { // in Narwhal or RingoJS v0.7.0- + for (key in punycode) { + punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); + } + } + } else { // in Rhino or a web browser + root.punycode = punycode; + } }(this)); |