UNPKG

madeline-ton

Version:

Pure JS client-side implementation of the Telegram TON blockchain protocol

349 lines (304 loc) 8.19 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _tools = require("../tools"); var Stream = /*#__PURE__*/ function () { /** * * @param {ArrayBuffer} aBuf Buffer */ function Stream(aBuf) { (0, _classCallCheck2["default"])(this, Stream); this.pos = 0; this.aBuf = aBuf || new ArrayBuffer(); this.iBuf = new Int32Array(this.aBuf); this.uBuf = new Uint32Array(this.aBuf); this.bBuf = new Uint8Array(this.aBuf); } /** * Read signed 32 bit integer * @returns number */ (0, _createClass2["default"])(Stream, [{ key: "readSignedInt", value: function readSignedInt() { return this.iBuf[this.pos++]; } /** * Read unsigned 32 bit integer * @returns number */ }, { key: "readUnsignedInt", value: function readUnsignedInt() { return this.uBuf[this.pos++]; } /** * Read signed 64 bit integer * In most cases, longs do not have to be used as numbers, just as blackbox values (access hash & so on). * No need to convert them to a bigint. * @returns number[] */ }, { key: "readSignedLong", value: function readSignedLong() { return [this.iBuf[this.pos++], this.iBuf[this.pos++]]; } /** * Read n*32 bit integer, returns n 32-bit integers * @returns number[] */ }, { key: "readUnsignedInts", value: function readUnsignedInts(length) { var res = this.uBuf.slice(this.pos, this.pos + length); this.pos += length; return res; } /** * Reads double (64-bit) * @returns number */ }, { key: "readDouble", value: function readDouble() { // We don't like unaligned data, and doubles are rare so just construct a new float64 view every time return new Float64Array(new Uint32Array(this.readSignedLong()).buffer)[0]; } /** * Read (32-bit aligned) bytes * @returns Uint8Array */ }, { key: "readBytes", value: function readBytes() { var bPos = this.pos * 4; var length = this.bBuf[bPos++]; if (length === 254) { length = this.readUnsignedInt() >> 8; bPos += 3; } var value = this.bBuf.slice(bPos, bPos + length); bPos += length; this.pos = Math.ceil(bPos / 4); return value; } /** * Read UTF8 string * @returns string */ }, { key: "readString", value: function readString() { var s = this.readBytes().map(String.fromCharCode).join(''); try { return decodeURIComponent(escape(s)); } catch (e) { return s; } } /** * Write signed 32-bit integer * @param {number} value Integer value * @returns Stream */ }, { key: "writeSignedInt", value: function writeSignedInt(value) { this.iBuf[this.pos++] = value; return this; } /** * Write unsigned 32-bit integer * @param {number} value Integer value * @returns Stream */ }, { key: "writeUnsignedInt", value: function writeUnsignedInt(value) { this.uBuf[this.pos++] = value; return this; } /** * Write signed 64-bit integer value * @param {Array|number} value 64-bit integer value (or one 32-bit integer value) * @returns Stream */ }, { key: "writeSignedLong", value: function writeSignedLong(value) { if (value.constructor === Array || value instanceof Int32Array) { // Blackbox value this.iBuf[this.pos++] = value[0]; this.iBuf[this.pos++] = value[1]; } else { // Assume plain 32-bit integer (ping_id and so on) this.iBuf[this.pos++] = 0; this.iBuf[this.pos++] = value; } return this; } /** * Write multiple 32-bit integer values * @param {Array} value Multiple 32-bit integer values * @returns Stream */ }, { key: "writeUnsignedInts", value: function writeUnsignedInts(value) { this.uBuf.set(value, this.pos); this.pos += value.length; return this; } /** * Encode double * @param {double} value Value to encode * @returns Stream */ }, { key: "writeDouble", value: function writeDouble(value) { var buf = new Uint32Array(new Float64Array([value]).buffer); this.uBuf[this.pos++] = buf[0]; this.uBuf[this.pos++] = buf[1]; return this; } /** * Write bytes * @param {Uint8Array} bytes Bytes array to encode * @returns Stream */ }, { key: "writeBytes", value: function writeBytes(bytes) { var length = bytes.length; var bPos = this.pos * 4; if (length <= 253) { this.bBuf[bPos++] = length; length++; } else { this.writeUnsignedInt(length << 8 | 0xFE); bPos += 4; length += 4; } length += (0, _tools.posMod)(-length, 4); length /= 4; // Length in int32 this.prepareLength(length - 1); // One int32 is already allocated by the parser this.bBuf.set(bytes, bPos); // No need to fill the padding (prolly) this.pos += length; return this; } /** * Encode UTF8 string * @param {string} string String to encode * @returns Stream */ }, { key: "writeString", value: function writeString(string) { string = unescape(encodeURIComponent(string)); var ln = string.length; var result = new Uint8Array(ln); for (var i = 0; i < ln; ++i) { result[i] = string.charCodeAt(i); } this.writeBytes(result); return this; } /** * Prepare buffer for serialization adding N more ints of free space * @param {number} more 32-bit ints to add * @returns Stream */ }, { key: "prepareLength", value: function prepareLength(more) { if (!more) return this; this.aBuf = (0, _tools.transfer)(this.aBuf, this.aBuf.byteLength + more * 4); this.iBuf = new Int32Array(this.aBuf); this.uBuf = new Uint32Array(this.aBuf); this.bBuf = new Uint8Array(this.aBuf); return this; } /** * Get current int32 stream size * @returns number */ }, { key: "getSize", value: function getSize() { return this.iBuf.length; } /** * Get current byte stream size * @returns number */ }, { key: "getByteLength", value: function getByteLength() { return this.iBuf.byteLength; } /** * Get current int32 stream position * @returns number */ }, { key: "getPos", value: function getPos() { return this.pos; } /** * Reset position */ }, { key: "reset", value: function reset() { this.pos = 0; return this; } /** * Gets buffer * @returns ArrayBuffer */ }, { key: "getBuffer", value: function getBuffer() { return this.aBuf; } /** * Switch endianness of integer * @param {number} n Number */ }], [{ key: "switcheroo", value: function switcheroo(n) { return n >> 24 & 0xff | n << 8 & 0xff0000 | n >> 8 & 0xff00 | n << 24 & 0xff000000; } }]); return Stream; }(); Stream.bigEndian = new Int8Array(new Uint16Array([0x1234]).buffer)[1] === 0x34; if (Stream.bigEndian) { // Big-endian hacks Stream.prototype.readSignedInt = function () { return this.switcheroo(this.iBuf[this.pos++]); }; Stream.prototype.writeSignedInt = function (value) { this.iBuf[this.pos++] = this.switcheroo(value); }; Stream.prototype.readUnsignedInt = function () { return this.switcheroo(this.uBuf[this.pos++]); }; Stream.prototype.writeUnsignedInt = function (value) { this.uBuf[this.pos++] = this.switcheroo(value); }; } var _default = Stream; exports["default"] = _default;