/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; module.metadata = { "stability": "experimental" }; const { Cu } = require("chrome"); const { TextEncoder, TextDecoder } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {}); exports.TextEncoder = TextEncoder; exports.TextDecoder = TextDecoder; function Buffer(subject, encoding) { var type = typeof(subject); switch (type) { case "number": // Create typed array of the given size if number. return Uint8Array(subject > 0 ? Math.floor(subject) : 0); case "string": // If string encode it and use buffer for the returned Uint8Array // to create a local patched version that acts like node buffer. encoding = encoding || "utf8"; return Uint8Array(TextEncoder(encoding).encode(subject).buffer); case "object": // If array or alike just make a copy with a local patched prototype. return Uint8Array(subject); default: throw new TypeError("must start with number, buffer, array or string"); } } exports.Buffer = Buffer; // Tests if `value` is a Buffer. Buffer.isBuffer = value => value instanceof Buffer // Returns true if the encoding is a valid encoding argument & false otherwise Buffer.isEncoding = encoding => !!ENCODINGS[String(encoding).toLowerCase()] // Gives the actual byte length of a string. encoding defaults to 'utf8'. // This is not the same as String.prototype.length since that returns the // number of characters in a string. Buffer.byteLength = (value, encoding = "utf8") => TextEncoder(encoding).encode(value).byteLength // Direct copy of the nodejs's buffer implementation: // https://github.com/joyent/node/blob/b255f4c10a80343f9ce1cee56d0288361429e214/lib/buffer.js#L146-L177 Buffer.concat = function(list, length) { if (!Array.isArray(list)) throw new TypeError('Usage: Buffer.concat(list[, length])'); if (typeof length === 'undefined') { length = 0; for (var i = 0; i < list.length; i++) length += list[i].length; } else { length = ~~length; } if (length < 0) length = 0; if (list.length === 0) return new Buffer(0); else if (list.length === 1) return list[0]; if (length < 0) throw new RangeError('length is not a positive number'); var buffer = new Buffer(length); var pos = 0; for (var i = 0; i < list.length; i++) { var buf = list[i]; buf.copy(buffer, pos); pos += buf.length; } return buffer; }; // Node buffer is very much like Uint8Array although it has bunch of methods // that typically can be used in combination with `DataView` while preserving // access by index. Since in SDK echo module has it's own set of bult-ins it // ok to patch ours to make it nodejs Buffer compatible. Buffer.prototype = Uint8Array.prototype; Object.defineProperties(Buffer.prototype, { view: { get: function() this._view || (this._view = DataView(this.buffer)) }, toString: { value: function(encoding, start, end) { encoding = !!encoding ? (encoding + '').toLowerCase() : "utf8"; start = Math.max(0, ~~start); end = Math.min(this.length, end === void(0) ? this.length : ~~end); return TextDecoder(encoding).decode(this.subarray(start, end)); } }, toJSON: { value: function() ({ type: "Buffer", data: Array.slice(this, 0) }) }, get: { value: function(offset) this[offset] }, set: { value: function(offset, value) this[offset] = value }, copy: { value: function(target, offset, start, end) Uint8Array.set(target, this.subarray(start, end), offset) }, slice: { value: Buffer.prototype.subarray }, write: { value: function(string, offset, length, encoding = "utf8") { if (typeof(offset) === "string") ([offset, length, encoding]) = [0, null, offset]; else if (typeof(length) === "string") ([length, encoding]) = [null, length]; offset = ~~offset; length = length || this.length - offset; let buffer = TextEncoder(encoding).encode(string); let result = Math.min(buffer.length, length); if (buffer.length !== length) buffer = buffer.subarray(0, length); Uint8Array.set(this, buffer, offset); return result; } }, fill: { value: function fill(value, start, end) { value = value || 0; start = start || 0; end = end || this.length; if (typeof(value) === "string") value = value.charCodeAt(0); if (typeof(value) !== "number" || isNaN(value)) throw TypeError("value is not a number"); if (end < start) throw new RangeError("end < start"); // Fill 0 bytes; we're done if (end === start) return 0; if (this.length == 0) return 0; if (start < 0 || start >= this.length) throw RangeError("start out of bounds"); if (end < 0 || end > this.length) throw RangeError("end out of bounds"); let index = start; while (index < end) this[index++] = value; } } }); // Define nodejs Buffer's getter and setter functions that just proxy // to internal DataView's equivalent methods. [["readUInt16LE", "getUint16", true], ["readUInt16BE", "getUint16", false], ["readInt16LE", "getInt16", true], ["readInt16BE", "getInt16", false], ["readUInt32LE", "getInt32", true], ["readUInt32BE", "getInt32", false], ["readInt32LE", "getInt32", true], ["readInt32BE", "getInt32", false], ["readFloatLE", "getFloat32", true], ["readFloatBE", "getFloat32", false], ["readDoubleLE", "getFloat64", true], ["readDoubleBE", "getFloat64", false], ["readUInt8", "getUint8"], ["readInt8", "getInt8"]].forEach(([alias, name, littleEndian]) => { Object.defineProperty(Buffer.prototype, alias, { value: function(offset) this.view[name](offset, littleEndian) }); }); [["writeUInt16LE", "setUint16", true], ["writeUInt16BE", "setUint16", false], ["writeInt16LE", "setInt16", true], ["writeInt16BE", "setInt16", false], ["writeUInt32LE", "setUint32", true], ["writeUInt32BE", "setUint32", false], ["writeInt32LE", "setInt32", true], ["writeInt32BE", "setInt32", false], ["writeFloatLE", "setFloat32", true], ["writeFloatBE", "setFloat32", false], ["writeDoubleLE", "setFloat64", true], ["writeDoubleBE", "setFloat64", false], ["writeUInt8", "setUint8"], ["writeInt8", "setInt8"]].forEach(([alias, name, littleEndian]) => { Object.defineProperty(Buffer.prototype, alias, { value: function(value, offset) this.view[name](offset, value, littleEndian) }); }); // List of supported encodings taken from: // http://mxr.mozilla.org/mozilla-central/source/dom/encoding/labelsencodings.properties const ENCODINGS = { "unicode-1-1-utf-8": 1, "utf-8": 1, "utf8": 1, "866": 1, "cp866": 1, "csibm866": 1, "ibm866": 1, "csisolatin2": 1, "iso-8859-2": 1, "iso-ir-101": 1, "iso8859-2": 1, "iso88592": 1, "iso_8859-2": 1, "iso_8859-2:1987": 1, "l2": 1, "latin2": 1, "csisolatin3": 1, "iso-8859-3": 1, "iso-ir-109": 1, "iso8859-3": 1, "iso88593": 1, "iso_8859-3": 1, "iso_8859-3:1988": 1, "l3": 1, "latin3": 1, "csisolatin4": 1, "iso-8859-4": 1, "iso-ir-110": 1, "iso8859-4": 1, "iso88594": 1, "iso_8859-4": 1, "iso_8859-4:1988": 1, "l4": 1, "latin4": 1, "csisolatincyrillic": 1, "cyrillic": 1, "iso-8859-5": 1, "iso-ir-144": 1, "iso8859-5": 1, "iso88595": 1, "iso_8859-5": 1, "iso_8859-5:1988": 1, "arabic": 1, "asmo-708": 1, "csiso88596e": 1, "csiso88596i": 1, "csisolatinarabic": 1, "ecma-114": 1, "iso-8859-6": 1, "iso-8859-6-e": 1, "iso-8859-6-i": 1, "iso-ir-127": 1, "iso8859-6": 1, "iso88596": 1, "iso_8859-6": 1, "iso_8859-6:1987": 1, "csisolatingreek": 1, "ecma-118": 1, "elot_928": 1, "greek": 1, "greek8": 1, "iso-8859-7": 1, "iso-ir-126": 1, "iso8859-7": 1, "iso88597": 1, "iso_8859-7": 1, "iso_8859-7:1987": 1, "sun_eu_greek": 1, "csiso88598e": 1, "csisolatinhebrew": 1, "hebrew": 1, "iso-8859-8": 1, "iso-8859-8-e": 1, "iso-ir-138": 1, "iso8859-8": 1, "iso88598": 1, "iso_8859-8": 1, "iso_8859-8:1988": 1, "visual": 1, "csiso88598i": 1, "iso-8859-8-i": 1, "logical": 1, "csisolatin6": 1, "iso-8859-10": 1, "iso-ir-157": 1, "iso8859-10": 1, "iso885910": 1, "l6": 1, "latin6": 1, "iso-8859-13": 1, "iso8859-13": 1, "iso885913": 1, "iso-8859-14": 1, "iso8859-14": 1, "iso885914": 1, "csisolatin9": 1, "iso-8859-15": 1, "iso8859-15": 1, "iso885915": 1, "iso_8859-15": 1, "l9": 1, "iso-8859-16": 1, "cskoi8r": 1, "koi": 1, "koi8": 1, "koi8-r": 1, "koi8_r": 1, "koi8-u": 1, "csmacintosh": 1, "mac": 1, "macintosh": 1, "x-mac-roman": 1, "dos-874": 1, "iso-8859-11": 1, "iso8859-11": 1, "iso885911": 1, "tis-620": 1, "windows-874": 1, "cp1250": 1, "windows-1250": 1, "x-cp1250": 1, "cp1251": 1, "windows-1251": 1, "x-cp1251": 1, "ansi_x3.4-1968": 1, "ascii": 1, "cp1252": 1, "cp819": 1, "csisolatin1": 1, "ibm819": 1, "iso-8859-1": 1, "iso-ir-100": 1, "iso8859-1": 1, "iso88591": 1, "iso_8859-1": 1, "iso_8859-1:1987": 1, "l1": 1, "latin1": 1, "us-ascii": 1, "windows-1252": 1, "x-cp1252": 1, "cp1253": 1, "windows-1253": 1, "x-cp1253": 1, "cp1254": 1, "csisolatin5": 1, "iso-8859-9": 1, "iso-ir-148": 1, "iso8859-9": 1, "iso88599": 1, "iso_8859-9": 1, "iso_8859-9:1989": 1, "l5": 1, "latin5": 1, "windows-1254": 1, "x-cp1254": 1, "cp1255": 1, "windows-1255": 1, "x-cp1255": 1, "cp1256": 1, "windows-1256": 1, "x-cp1256": 1, "cp1257": 1, "windows-1257": 1, "x-cp1257": 1, "cp1258": 1, "windows-1258": 1, "x-cp1258": 1, "x-mac-cyrillic": 1, "x-mac-ukrainian": 1, "chinese": 1, "csgb2312": 1, "csiso58gb231280": 1, "gb2312": 1, "gb_2312": 1, "gb_2312-80": 1, "gbk": 1, "iso-ir-58": 1, "x-gbk": 1, "gb18030": 1, "hz-gb-2312": 1, "big5": 1, "big5-hkscs": 1, "cn-big5": 1, "csbig5": 1, "x-x-big5": 1, "cseucpkdfmtjapanese": 1, "euc-jp": 1, "x-euc-jp": 1, "csiso2022jp": 1, "iso-2022-jp": 1, "csshiftjis": 1, "ms_kanji": 1, "shift-jis": 1, "shift_jis": 1, "sjis": 1, "windows-31j": 1, "x-sjis": 1, "cseuckr": 1, "csksc56011987": 1, "euc-kr": 1, "iso-ir-149": 1, "korean": 1, "ks_c_5601-1987": 1, "ks_c_5601-1989": 1, "ksc5601": 1, "ksc_5601": 1, "windows-949": 1, "csiso2022kr": 1, "iso-2022-kr": 1, "utf-16": 1, "utf-16le": 1, "utf-16be": 1, "x-user-defined": 1 };