UNPKG

int-cli

Version:

INT is the new generation of bottom-up created system of IoT and blockchain

440 lines (439 loc) 12.4 kB
/*! * reader.js - buffer reader for bcoin * Copyright (c) 2014-2015, Fedor Indutny (MIT License) * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). * https://github.com/bcoin-org/bcoin */ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); const assert = require("assert"); const encoding_1 = require("./encoding"); const digest = require("./digest"); const bignumber_js_1 = require("bignumber.js"); const EMPTY = Buffer.alloc(0); /** * An object that allows reading of buffers in a sane manner. * @alias module:utils.BufferReader * @constructor * @param {Buffer} data * @param {Boolean?} zeroCopy - Do not reallocate buffers when * slicing. Note that this can lead to memory leaks if not used * carefully. */ class BufferReader { constructor(data, zeroCopy) { if (!(this instanceof BufferReader)) { return new BufferReader(data, zeroCopy); } assert(Buffer.isBuffer(data), 'Must pass a Buffer.'); this.data = data; this.offset = 0; this.zeroCopy = zeroCopy || false; this.stack = []; } /** * Assertion. * @param {Boolean} value */ assert(value) { if (!value) { throw new encoding_1.EncodingError(this.offset, 'Out of bounds read', assert); } } /** * Assertion. * @param {Boolean} value * @param {String} reason */ enforce(value, reason) { if (!value) { throw new encoding_1.EncodingError(this.offset, reason); } } /** * Get total size of passed-in Buffer. * @returns {Buffer} */ getSize() { return this.data.length; } /** * Calculate number of bytes left to read. * @returns {Number} */ left() { this.assert(this.offset <= this.data.length); return this.data.length - this.offset; } /** * Seek to a position to read from by offset. * @param {Number} off - Offset (positive or negative). */ seek(off) { this.assert(this.offset + off >= 0); this.assert(this.offset + off <= this.data.length); this.offset += off; return off; } /** * Mark the current starting position. */ start() { this.stack.push(this.offset); return this.offset; } /** * Stop reading. Pop the start position off the stack * and calculate the size of the data read. * @returns {Number} Size. * @throws on empty stack. */ end() { assert(this.stack.length > 0); const start = this.stack.pop(); return this.offset - start; } /** * Stop reading. Pop the start position off the stack * and return the data read. * @param {Bolean?} zeroCopy - Do a fast buffer * slice instead of allocating a new buffer (warning: * may cause memory leaks if not used with care). * @returns {Buffer} Data read. * @throws on empty stack. */ endData(zeroCopy) { assert(this.stack.length > 0); const start = this.stack.pop(); const end = this.offset; const size = end - start; const data = this.data; if (size === data.length) { return data; } if (this.zeroCopy || zeroCopy) { return data.slice(start, end); } const ret = Buffer.allocUnsafe(size); data.copy(ret, 0, start, end); return ret; } /** * Destroy the reader. Remove references to the data. */ destroy() { this.data = EMPTY; this.offset = 0; this.stack.length = 0; } /** * Read uint8. * @returns {Number} */ readU8() { this.assert(this.offset + 1 <= this.data.length); const ret = this.data[this.offset]; this.offset += 1; return ret; } /** * Read uint16le. * @returns {Number} */ readU16() { this.assert(this.offset + 2 <= this.data.length); const ret = this.data.readUInt16LE(this.offset, true); this.offset += 2; return ret; } /** * Read uint16be. * @returns {Number} */ readU16BE() { this.assert(this.offset + 2 <= this.data.length); const ret = this.data.readUInt16BE(this.offset, true); this.offset += 2; return ret; } /** * Read uint32le. * @returns {Number} */ readU32() { this.assert(this.offset + 4 <= this.data.length); const ret = this.data.readUInt32LE(this.offset, true); this.offset += 4; return ret; } /** * Read uint32be. * @returns {Number} */ readU32BE() { this.assert(this.offset + 4 <= this.data.length); const ret = this.data.readUInt32BE(this.offset, true); this.offset += 4; return ret; } /** * Read uint64le as a js number. * @returns {Number} * @throws on num > MAX_SAFE_INTEGER */ readU64() { this.assert(this.offset + 8 <= this.data.length); const ret = encoding_1.Encoding.readU64(this.data, this.offset); this.offset += 8; return ret; } /** * Read uint64be as a js number. * @returns {Number} * @throws on num > MAX_SAFE_INTEGER */ readU64BE() { this.assert(this.offset + 8 <= this.data.length); const ret = encoding_1.Encoding.readU64BE(this.data, this.offset); this.offset += 8; return ret; } /** * Read int8. * @returns {Number} */ readI8() { this.assert(this.offset + 1 <= this.data.length); const ret = this.data.readInt8(this.offset, true); this.offset += 1; return ret; } /** * Read int16le. * @returns {Number} */ readI16() { this.assert(this.offset + 2 <= this.data.length); const ret = this.data.readInt16LE(this.offset, true); this.offset += 2; return ret; } /** * Read int16be. * @returns {Number} */ readI16BE() { this.assert(this.offset + 2 <= this.data.length); const ret = this.data.readInt16BE(this.offset, true); this.offset += 2; return ret; } /** * Read int32le. * @returns {Number} */ readI32() { this.assert(this.offset + 4 <= this.data.length); const ret = this.data.readInt32LE(this.offset, true); this.offset += 4; return ret; } /** * Read int32be. * @returns {Number} */ readI32BE() { this.assert(this.offset + 4 <= this.data.length); const ret = this.data.readInt32BE(this.offset, true); this.offset += 4; return ret; } /** * Read int64le as a js number. * @returns {Number} * @throws on num > MAX_SAFE_INTEGER */ readI64() { this.assert(this.offset + 8 <= this.data.length); const ret = encoding_1.Encoding.readI64(this.data, this.offset); this.offset += 8; return ret; } /** * Read int64be as a js number. * @returns {Number} * @throws on num > MAX_SAFE_INTEGER */ readI64BE() { this.assert(this.offset + 8 <= this.data.length); const ret = encoding_1.Encoding.readI64BE(this.data, this.offset); this.offset += 8; return ret; } /** * Read float le. * @returns {Number} */ readFloat() { this.assert(this.offset + 4 <= this.data.length); const ret = this.data.readFloatLE(this.offset, true); this.offset += 4; return ret; } /** * Read float be. * @returns {Number} */ readFloatBE() { this.assert(this.offset + 4 <= this.data.length); const ret = this.data.readFloatBE(this.offset, true); this.offset += 4; return ret; } /** * Read double float le. * @returns {Number} */ readDouble() { this.assert(this.offset + 8 <= this.data.length); const ret = this.data.readDoubleLE(this.offset, true); this.offset += 8; return ret; } /** * Read double float be. * @returns {Number} */ readDoubleBE() { this.assert(this.offset + 8 <= this.data.length); const ret = this.data.readDoubleBE(this.offset, true); this.offset += 8; return ret; } /** * Read a varint. * @returns {Number} */ readVarint() { const { size, value } = encoding_1.Encoding.readVarint(this.data, this.offset); this.offset += size; return value; } /** * Read a varint (type 2). * @returns {Number} */ readVarint2() { const { size, value } = encoding_1.Encoding.readVarint2(this.data, this.offset); this.offset += size; return value; } /** * Read N bytes (will do a fast slice if zero copy). * @param {Number} size * @param {Bolean?} zeroCopy - Do a fast buffer * slice instead of allocating a new buffer (warning: * may cause memory leaks if not used with care). * @returns {Buffer} */ readBytes(size, zeroCopy) { assert(size >= 0); this.assert(this.offset + size <= this.data.length); let ret; if (this.zeroCopy || zeroCopy) { ret = this.data.slice(this.offset, this.offset + size); } else { ret = Buffer.allocUnsafe(size); this.data.copy(ret, 0, this.offset, this.offset + size); } this.offset += size; return ret; } /** * Read a varint number of bytes (will do a fast slice if zero copy). * @param {Bolean?} zeroCopy - Do a fast buffer * slice instead of allocating a new buffer (warning: * may cause memory leaks if not used with care). * @returns {Buffer} */ readVarBytes(zeroCopy) { return this.readBytes(this.readVarint(), zeroCopy); } /** * Read a string. * @param {String} enc - Any buffer-supported Encoding. * @param {Number} size * @returns {String} */ readString(enc, size) { assert(size >= 0); this.assert(this.offset + size <= this.data.length); const ret = this.data.toString(enc, this.offset, this.offset + size); this.offset += size; return ret; } readHash(enc) { if (enc) { return this.readString(enc, 32); } return this.readBytes(32); } /** * Read string of a varint length. * @param {String} enc - Any buffer-supported Encoding. * @param {Number?} limit - Size limit. * @returns {String} */ readVarString(enc, limit) { const size = this.readVarint(); this.enforce(!limit || size <= limit, 'String exceeds limit.'); return this.readString(enc, size); } readBigNumber() { let str = this.readVarString(); return new bignumber_js_1.BigNumber(str); } /** * Read a null-terminated string. * @param {String} enc - Any buffer-supported Encoding. * @returns {String} */ readNullString(enc) { this.assert(this.offset + 1 <= this.data.length); let i = this.offset; for (; i < this.data.length; i++) { if (this.data[i] === 0) { break; } } this.assert(i !== this.data.length); const ret = this.readString(enc, i - this.offset); this.offset = i + 1; return ret; } /** * Create a checksum from the last start position. * @returns {Number} Checksum. */ createChecksum() { let start = 0; if (this.stack.length > 0) { start = this.stack[this.stack.length - 1]; } const data = this.data.slice(start, this.offset); return digest.hash256(data).readUInt32LE(0, true); } /** * Verify a 4-byte checksum against a calculated checksum. * @returns {Number} checksum * @throws on bad checksum */ verifyChecksum() { const chk = this.createChecksum(); const checksum = this.readU32(); this.enforce(chk === checksum, 'Checksum mismatch.'); return checksum; } } exports.BufferReader = BufferReader;