diff --git a/dist/converse.js b/dist/converse.js index c54607e16..8ba6d04b8 100644 --- a/dist/converse.js +++ b/dist/converse.js @@ -7507,6 +7507,205 @@ return Promise$2; /***/ }), +/***/ "./node_modules/fast-text-encoding/text.js": +/*!*************************************************!*\ + !*** ./node_modules/fast-text-encoding/text.js ***! + \*************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +/* WEBPACK VAR INJECTION */(function(global) {/* + * Copyright 2017 Sam Thorogood. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/** + * @fileoverview Polyfill for TextEncoder and TextDecoder. + * + * You probably want `text.min.js`, and not this file directly. + */ + +(function(scope) { +'use strict'; + +// fail early +if (scope['TextEncoder'] && scope['TextDecoder']) { + return false; +} + +/** + * @constructor + * @param {string=} utfLabel + */ +function FastTextEncoder(utfLabel='utf-8') { + if (utfLabel !== 'utf-8') { + throw new RangeError( + `Failed to construct 'TextEncoder': The encoding label provided ('${utfLabel}') is invalid.`); + } +} + +Object.defineProperty(FastTextEncoder.prototype, 'encoding', {value: 'utf-8'}); + +/** + * @param {string} string + * @param {{stream: boolean}=} options + * @return {!Uint8Array} + */ +FastTextEncoder.prototype.encode = function(string, options={stream: false}) { + if (options.stream) { + throw new Error(`Failed to encode: the 'stream' option is unsupported.`); + } + + let pos = 0; + const len = string.length; + const out = []; + + let at = 0; // output position + let tlen = Math.max(32, len + (len >> 1) + 7); // 1.5x size + let target = new Uint8Array((tlen >> 3) << 3); // ... but at 8 byte offset + + while (pos < len) { + let value = string.charCodeAt(pos++); + if (value >= 0xd800 && value <= 0xdbff) { + // high surrogate + if (pos < len) { + const extra = string.charCodeAt(pos); + if ((extra & 0xfc00) === 0xdc00) { + ++pos; + value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000; + } + } + if (value >= 0xd800 && value <= 0xdbff) { + continue; // drop lone surrogate + } + } + + // expand the buffer if we couldn't write 4 bytes + if (at + 4 > target.length) { + tlen += 8; // minimum extra + tlen *= (1.0 + (pos / string.length) * 2); // take 2x the remaining + tlen = (tlen >> 3) << 3; // 8 byte offset + + const update = new Uint8Array(tlen); + update.set(target); + target = update; + } + + if ((value & 0xffffff80) === 0) { // 1-byte + target[at++] = value; // ASCII + continue; + } else if ((value & 0xfffff800) === 0) { // 2-byte + target[at++] = ((value >> 6) & 0x1f) | 0xc0; + } else if ((value & 0xffff0000) === 0) { // 3-byte + target[at++] = ((value >> 12) & 0x0f) | 0xe0; + target[at++] = ((value >> 6) & 0x3f) | 0x80; + } else if ((value & 0xffe00000) === 0) { // 4-byte + target[at++] = ((value >> 18) & 0x07) | 0xf0; + target[at++] = ((value >> 12) & 0x3f) | 0x80; + target[at++] = ((value >> 6) & 0x3f) | 0x80; + } else { + // FIXME: do we care + continue; + } + + target[at++] = (value & 0x3f) | 0x80; + } + + return target.slice(0, at); +} + +/** + * @constructor + * @param {string=} utfLabel + * @param {{fatal: boolean}=} options + */ +function FastTextDecoder(utfLabel='utf-8', options={fatal: false}) { + if (utfLabel !== 'utf-8') { + throw new RangeError( + `Failed to construct 'TextDecoder': The encoding label provided ('${utfLabel}') is invalid.`); + } + if (options.fatal) { + throw new Error(`Failed to construct 'TextDecoder': the 'fatal' option is unsupported.`); + } +} + +Object.defineProperty(FastTextDecoder.prototype, 'encoding', {value: 'utf-8'}); + +Object.defineProperty(FastTextDecoder.prototype, 'fatal', {value: false}); + +Object.defineProperty(FastTextDecoder.prototype, 'ignoreBOM', {value: false}); + +/** + * @param {(!ArrayBuffer|!ArrayBufferView)} buffer + * @param {{stream: boolean}=} options + */ +FastTextDecoder.prototype.decode = function(buffer, options={stream: false}) { + if (options['stream']) { + throw new Error(`Failed to decode: the 'stream' option is unsupported.`); + } + + const bytes = new Uint8Array(buffer); + let pos = 0; + const len = bytes.length; + const out = []; + + while (pos < len) { + const byte1 = bytes[pos++]; + if (byte1 === 0) { + break; // NULL + } + + if ((byte1 & 0x80) === 0) { // 1-byte + out.push(byte1); + } else if ((byte1 & 0xe0) === 0xc0) { // 2-byte + const byte2 = bytes[pos++] & 0x3f; + out.push(((byte1 & 0x1f) << 6) | byte2); + } else if ((byte1 & 0xf0) === 0xe0) { + const byte2 = bytes[pos++] & 0x3f; + const byte3 = bytes[pos++] & 0x3f; + out.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3); + } else if ((byte1 & 0xf8) === 0xf0) { + const byte2 = bytes[pos++] & 0x3f; + const byte3 = bytes[pos++] & 0x3f; + const byte4 = bytes[pos++] & 0x3f; + + // this can be > 0xffff, so possibly generate surrogates + let codepoint = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4; + if (codepoint > 0xffff) { + // codepoint &= ~0x10000; + codepoint -= 0x10000; + out.push((codepoint >>> 10) & 0x3ff | 0xd800) + codepoint = 0xdc00 | codepoint & 0x3ff; + } + out.push(codepoint); + } else { + // FIXME: we're ignoring this + } + } + + return String.fromCharCode.apply(null, out); +} + +scope['TextEncoder'] = FastTextEncoder; +scope['TextDecoder'] = FastTextDecoder; + +}(typeof window !== 'undefined' ? window : (typeof global !== 'undefined' ? global : this))); + +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack/buildin/global.js */ "./node_modules/webpack/buildin/global.js"))) + +/***/ }), + /***/ "./node_modules/filesize/lib/filesize.js": /*!***********************************************!*\ !*** ./node_modules/filesize/lib/filesize.js ***! @@ -81471,12 +81670,12 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /*global define, escape, window, Uint8Array */ (function (root, factory) { if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! sizzle */ "./node_modules/sizzle/dist/sizzle.js"), __webpack_require__(/*! es6-promise */ "./node_modules/es6-promise/dist/es6-promise.auto.js"), __webpack_require__(/*! lodash.noconflict */ "./src/lodash.noconflict.js"), __webpack_require__(/*! backbone */ "./node_modules/backbone/backbone.js"), __webpack_require__(/*! strophe */ "./node_modules/strophe.js/strophe.js"), __webpack_require__(/*! uri */ "./node_modules/urijs/src/URI.js"), __webpack_require__(/*! templates/audio.html */ "./src/templates/audio.html"), __webpack_require__(/*! templates/file.html */ "./src/templates/file.html"), __webpack_require__(/*! templates/image.html */ "./src/templates/image.html"), __webpack_require__(/*! templates/video.html */ "./src/templates/video.html")], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! sizzle */ "./node_modules/sizzle/dist/sizzle.js"), __webpack_require__(/*! es6-promise */ "./node_modules/es6-promise/dist/es6-promise.auto.js"), __webpack_require__(/*! fast-text-encoding */ "./node_modules/fast-text-encoding/text.js"), __webpack_require__(/*! lodash.noconflict */ "./src/lodash.noconflict.js"), __webpack_require__(/*! backbone */ "./node_modules/backbone/backbone.js"), __webpack_require__(/*! strophe */ "./node_modules/strophe.js/strophe.js"), __webpack_require__(/*! uri */ "./node_modules/urijs/src/URI.js"), __webpack_require__(/*! templates/audio.html */ "./src/templates/audio.html"), __webpack_require__(/*! templates/file.html */ "./src/templates/file.html"), __webpack_require__(/*! templates/image.html */ "./src/templates/image.html"), __webpack_require__(/*! templates/video.html */ "./src/templates/video.html")], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else {} -})(void 0, function (sizzle, Promise, _, Backbone, Strophe, URI, tpl_audio, tpl_file, tpl_image, tpl_video) { +})(void 0, function (sizzle, Promise, FastTextEncoding, _, Backbone, Strophe, URI, tpl_audio, tpl_file, tpl_image, tpl_video) { "use strict"; Strophe = Strophe.Strophe; @@ -82300,17 +82499,11 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ }; u.arrayBufferToString = function (ab) { - return new Uint8Array(ab).reduce((data, byte) => data + String.fromCharCode(byte), ''); + return new TextDecoder("utf-8").decode(ab); }; u.stringToArrayBuffer = function (string) { - const len = string.length, - bytes = new Uint8Array(len); - - for (let i = 0; i < len; i++) { - bytes[i] = string.charCodeAt(i); - } - + const bytes = new TextEncoder("utf-8").encode(string); return bytes.buffer; }; diff --git a/package-lock.json b/package-lock.json index bfd9483c5..e46882756 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4078,6 +4078,11 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-text-encoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", + "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==" + }, "fastparse": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", diff --git a/package.json b/package.json index 5933733c5..81d337774 100644 --- a/package.json +++ b/package.json @@ -90,5 +90,8 @@ "webpack": "^4.0.1", "webpack-cli": "^2.1.4", "xss": "^0.3.3" + }, + "dependencies": { + "fast-text-encoding": "^1.0.0" } } diff --git a/src/utils/core.js b/src/utils/core.js index 3ca5f4c67..0f8d228be 100644 --- a/src/utils/core.js +++ b/src/utils/core.js @@ -12,6 +12,7 @@ define([ "sizzle", "es6-promise", + "fast-text-encoding", "lodash.noconflict", "backbone", "strophe", @@ -39,6 +40,7 @@ root.converse_utils = factory( root.sizzle, root.Promise, + null, root._, root.Backbone, Strophe @@ -47,6 +49,7 @@ }(this, function ( sizzle, Promise, + FastTextEncoding, _, Backbone, Strophe, @@ -869,17 +872,12 @@ }; u.arrayBufferToString = function (ab) { - return (new Uint8Array(ab)).reduce((data, byte) => data + String.fromCharCode(byte), ''); + return new TextDecoder("utf-8").decode(ab); }; u.stringToArrayBuffer = function (string) { - const len = string.length, - bytes = new Uint8Array(len); - - for (let i = 0; i < len; i++) { - bytes[i] = string.charCodeAt(i) - } - return bytes.buffer + const bytes = new TextEncoder("utf-8").encode(string); + return bytes.buffer; }; u.arrayBufferToBase64 = function (ab) { diff --git a/webpack.config.js b/webpack.config.js index 234d5f86a..cf1c0fad5 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -80,7 +80,6 @@ const config = { "IPv6": path.resolve(__dirname, "node_modules/urijs/src/IPv6"), "SecondLevelDomains": path.resolve(__dirname, "node_modules/urijs/src/SecondLevelDomains"), "awesomplete": path.resolve(__dirname, "node_modules/awesomplete-avoid-xss/awesomplete"), - "formdata-polyfill": path.resolve(__dirname, "node_modules/formdata-polyfill/FormData"), "backbone": path.resolve(__dirname, "node_modules/backbone/backbone"), "backbone.browserStorage": path.resolve(__dirname, "node_modules/backbone.browserStorage/backbone.browserStorage"), "backbone.nativeview": path.resolve(__dirname, "node_modules/backbone.nativeview/backbone.nativeview"), @@ -91,6 +90,8 @@ const config = { "crypto": path.resolve(__dirname, "node_modules/otr/build/dep/crypto"), "es6-promise": path.resolve(__dirname, "node_modules/es6-promise/dist/es6-promise.auto"), "filesize": path.resolve(__dirname, "node_modules/filesize/lib/filesize"), + "fast-text-encoding": path.resolve(__dirname, "node_modules/fast-text-encoding/text"), + "formdata-polyfill": path.resolve(__dirname, "node_modules/formdata-polyfill/FormData"), "jed": path.resolve(__dirname, "node_modules/jed/jed"), "jquery": path.resolve(__dirname, "src/jquery-stub"), "lodash": path.resolve(__dirname, "node_modules/lodash/lodash"), @@ -107,14 +108,14 @@ const config = { "snabbdom-style": path.resolve(__dirname, "node_modules/snabbdom/dist/snabbdom-style"), "strophe": path.resolve(__dirname, "node_modules/strophe.js/strophe"), "strophe.ping": path.resolve(__dirname, "node_modules/strophejs-plugin-ping/strophe.ping"), - "utils/emoji": path.resolve(__dirname, "src/utils/emoji"), - "utils/form": path.resolve(__dirname, "src/utils/form"), - "utils/muc": path.resolve(__dirname, "src/utils/muc"), "strophe.rsm": path.resolve(__dirname, "node_modules/strophejs-plugin-rsm/strophe.rsm"), "tovnode": path.resolve(__dirname, "node_modules/snabbdom/dist/tovnode"), "underscore": path.resolve(__dirname, "src/underscore-shim"), "uri": path.resolve(__dirname, "node_modules/urijs/src/URI"), "utils/core": path.resolve(__dirname, "src/utils/core"), + "utils/emoji": path.resolve(__dirname, "src/utils/emoji"), + "utils/form": path.resolve(__dirname, "src/utils/form"), + "utils/muc": path.resolve(__dirname, "src/utils/muc"), "vdom-parser": path.resolve(__dirname, "node_modules/vdom-parser/dist"), "xss": path.resolve(__dirname, "node_modules/xss/dist/xss") }