madeline-ton
Version:
Pure JS client-side implementation of the Telegram TON blockchain protocol
349 lines (304 loc) • 8.19 kB
JavaScript
"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;