itns-sidechain/lib/utils/encoding.js

1072 lines
20 KiB
JavaScript
Raw Normal View History

2016-11-19 05:29:16 -08:00
/*!
* encoding.js - encoding utils for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
2017-02-03 22:47:26 -08:00
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
2016-11-19 05:29:16 -08:00
* https://github.com/bcoin-org/bcoin
*/
'use strict';
2017-02-03 22:47:26 -08:00
/**
* @module utils/encoding
*/
2017-06-29 20:54:07 -07:00
const BN = require('bn.js');
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER;
const encoding = exports;
2016-11-19 05:29:16 -08:00
2017-01-06 09:57:55 -08:00
/**
* An empty buffer.
* @const {Buffer}
* @default
*/
encoding.DUMMY = Buffer.from([0]);
2017-01-06 09:57:55 -08:00
/**
* A hash of all zeroes with a `1` at the
* end (used for the SIGHASH_SINGLE bug).
* @const {Buffer}
* @default
*/
encoding.ONE_HASH = Buffer.from(
2017-01-06 09:57:55 -08:00
'0100000000000000000000000000000000000000000000000000000000000000',
'hex'
);
/**
* A hash of all zeroes.
* @const {Buffer}
* @default
*/
encoding.ZERO_HASH = Buffer.from(
2017-01-06 09:57:55 -08:00
'0000000000000000000000000000000000000000000000000000000000000000',
'hex'
);
/**
* A hash of all 0xff.
* @const {Buffer}
* @default
*/
encoding.MAX_HASH = Buffer.from(
2017-01-06 09:57:55 -08:00
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'hex'
);
/**
* A hash of all zeroes.
* @const {String}
* @default
*/
encoding.NULL_HASH =
'0000000000000000000000000000000000000000000000000000000000000000';
/**
* A hash of all 0xff.
* @const {String}
* @default
*/
encoding.HIGH_HASH =
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
/**
* A hash of all zeroes.
* @const {Buffer}
* @default
*/
encoding.ZERO_HASH160 = Buffer.from(
2017-01-06 09:57:55 -08:00
'0000000000000000000000000000000000000000',
'hex'
);
/**
* A hash of all 0xff.
* @const {String}
* @default
*/
encoding.MAX_HASH160 = Buffer.from(
2017-01-06 09:57:55 -08:00
'ffffffffffffffffffffffffffffffffffffffff',
'hex'
);
/**
* A hash of all zeroes.
* @const {String}
* @default
*/
encoding.NULL_HASH160 = '0000000000000000000000000000000000000000';
/**
* A hash of all 0xff.
* @const {String}
* @default
*/
encoding.HIGH_HASH160 = 'ffffffffffffffffffffffffffffffffffffffff';
/**
* A compressed pubkey of all zeroes.
* @const {Buffer}
* @default
*/
encoding.ZERO_KEY = Buffer.from(
2017-01-06 09:57:55 -08:00
'000000000000000000000000000000000000000000000000000000000000000000',
'hex'
);
/**
* A 73 byte signature of all zeroes.
* @const {Buffer}
* @default
*/
encoding.ZERO_SIG = Buffer.from(''
2017-01-06 09:57:55 -08:00
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '000000000000000000',
'hex'
);
/**
* A 64 byte signature of all zeroes.
* @const {Buffer}
* @default
*/
encoding.ZERO_SIG64 = Buffer.from(''
2017-01-06 09:57:55 -08:00
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000',
'hex'
);
/**
* 4 zero bytes.
* @const {Buffer}
* @default
*/
encoding.ZERO_U32 = Buffer.from('00000000', 'hex');
2017-01-06 09:57:55 -08:00
/**
* 8 zero bytes.
* @const {Buffer}
* @default
*/
encoding.ZERO_U64 = Buffer.from('0000000000000000', 'hex');
2017-01-06 09:57:55 -08:00
2016-12-02 04:23:41 -08:00
/**
* Read uint64 as a js number.
* @private
2016-11-19 05:29:16 -08:00
* @param {Buffer} data
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @param {Boolean} force53 - Read only 53 bits, but maintain the sign.
* @param {Boolean} be
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding._readU64 = function _readU64(data, off, force53, be) {
2017-06-29 20:54:07 -07:00
let hi, lo;
2016-12-02 04:23:41 -08:00
if (be) {
hi = data.readUInt32BE(off, true);
lo = data.readUInt32BE(off + 4, true);
} else {
hi = data.readUInt32LE(off + 4, true);
lo = data.readUInt32LE(off, true);
}
if (force53)
hi &= 0x1fffff;
2017-03-15 06:49:46 -07:00
enforce((hi & 0xffe00000) === 0, off, 'Number exceeds 2^53-1');
2016-12-02 04:23:41 -08:00
return (hi * 0x100000000) + lo;
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Read uint64le as a js number.
2016-11-19 05:29:16 -08:00
* @param {Buffer} data
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding.readU64 = function readU64(data, off) {
return encoding._readU64(data, off, false, false);
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Read uint64be as a js number.
2016-11-19 05:29:16 -08:00
* @param {Buffer} data
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding.readU64BE = function readU64BE(data, off) {
return encoding._readU64(data, off, false, true);
};
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
/**
* Read uint64le as a js number (limit at 53 bits).
* @param {Buffer} data
* @param {Number} off
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.readU53 = function readU53(data, off) {
return encoding._readU64(data, off, true, false);
};
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
/**
* Read uint64be as a js number (limit at 53 bits).
* @param {Buffer} data
* @param {Number} off
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.readU53BE = function readU53BE(data, off) {
return encoding._readU64(data, off, true, true);
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Read int64 as a js number.
* @private
2016-11-19 05:29:16 -08:00
* @param {Buffer} data
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @param {Boolean} force53 - Read only 53 bits, but maintain the sign.
* @param {Boolean} be
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding._read64 = function _read64(data, off, force53, be) {
2017-06-29 20:54:07 -07:00
let hi, lo;
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
if (be) {
hi = data.readUInt32BE(off, true);
lo = data.readUInt32BE(off + 4, true);
} else {
hi = data.readUInt32LE(off + 4, true);
lo = data.readUInt32LE(off, true);
}
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
if (hi & 0x80000000) {
hi = ~hi >>> 0;
lo = ~lo >>> 0;
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
if (force53)
hi &= 0x1fffff;
2016-11-19 05:29:16 -08:00
2017-03-15 06:49:46 -07:00
enforce((hi & 0xffe00000) === 0, off, 'Number exceeds 2^53-1');
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
return -(hi * 0x100000000 + lo + 1);
}
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
if (force53)
hi &= 0x1fffff;
2016-11-19 05:29:16 -08:00
2017-03-15 06:49:46 -07:00
enforce((hi & 0xffe00000) === 0, off, 'Number exceeds 2^53-1');
2016-12-02 04:23:41 -08:00
return hi * 0x100000000 + lo;
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Read int64be as a js number.
* @param {Buffer} data
* @param {Number} off
* @returns {Number}
2016-11-19 05:29:16 -08:00
* @throws on num > MAX_SAFE_INTEGER
*/
2016-12-02 04:23:41 -08:00
encoding.read64 = function read64(data, off) {
return encoding._read64(data, off, false, false);
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Read int64be as a js number.
* @param {Buffer} data
* @param {Number} off
* @returns {Number}
2016-11-19 05:29:16 -08:00
* @throws on num > MAX_SAFE_INTEGER
*/
2016-12-02 04:23:41 -08:00
encoding.read64BE = function read64BE(data, off) {
return encoding._read64(data, off, false, true);
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Read int64be as a js number (limit at 53 bits).
* @param {Buffer} data
* @param {Number} off
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding.read53 = function read53(data, off) {
return encoding._read64(data, off, true, false);
};
2016-11-19 05:29:16 -08:00
/**
2016-12-02 04:23:41 -08:00
* Read int64be as a js number (limit at 53 bits).
* @param {Buffer} data
* @param {Number} off
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding.read53BE = function read53BE(data, off) {
return encoding._read64(data, off, true, true);
};
2016-11-19 05:29:16 -08:00
/**
2016-12-02 04:23:41 -08:00
* Write a javascript number as an int64.
* @private
* @param {Buffer} dst
* @param {Number} num
* @param {Number} off
* @param {Boolean} be
* @returns {Number} Buffer offset.
2016-11-19 05:29:16 -08:00
* @throws on num > MAX_SAFE_INTEGER
*/
2016-12-02 04:23:41 -08:00
encoding._write64 = function _write64(dst, num, off, be) {
2017-06-29 20:54:07 -07:00
let negative = num < 0;
let hi, lo;
2016-11-19 05:29:16 -08:00
if (negative) {
num = -num;
num -= 1;
}
enforce(num <= MAX_SAFE_INTEGER, off, 'Number exceeds 2^53-1');
2016-11-19 05:29:16 -08:00
2017-06-27 01:26:34 -07:00
hi = (num * (1 / 0x100000000)) | 0;
lo = num | 0;
2016-11-19 05:29:16 -08:00
if (negative) {
2017-06-27 01:26:34 -07:00
hi = ~hi;
lo = ~lo;
2016-11-19 05:29:16 -08:00
}
if (be) {
2016-12-02 04:23:41 -08:00
dst[off++] = hi >>> 24;
dst[off++] = (hi >> 16) & 0xff;
dst[off++] = (hi >> 8) & 0xff;
dst[off++] = hi & 0xff;
dst[off++] = lo >>> 24;
dst[off++] = (lo >> 16) & 0xff;
dst[off++] = (lo >> 8) & 0xff;
dst[off++] = lo & 0xff;
2016-11-19 05:29:16 -08:00
} else {
2016-12-02 04:23:41 -08:00
dst[off++] = lo & 0xff;
dst[off++] = (lo >> 8) & 0xff;
dst[off++] = (lo >> 16) & 0xff;
dst[off++] = lo >>> 24;
dst[off++] = hi & 0xff;
dst[off++] = (hi >> 8) & 0xff;
dst[off++] = (hi >> 16) & 0xff;
dst[off++] = hi >>> 24;
2016-11-19 05:29:16 -08:00
}
2016-12-02 04:23:41 -08:00
return off;
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Write a javascript number as a uint64le.
* @param {Buffer} dst
* @param {Number} num
* @param {Number} off
* @returns {Number} Buffer offset.
2016-11-19 05:29:16 -08:00
* @throws on num > MAX_SAFE_INTEGER
*/
2016-12-02 04:23:41 -08:00
encoding.writeU64 = function writeU64(dst, num, off) {
return encoding._write64(dst, num, off, false);
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Write a javascript number as a uint64be.
* @param {Buffer} dst
* @param {Number} num
2016-11-19 05:29:16 -08:00
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @returns {Number} Buffer offset.
2016-11-19 05:29:16 -08:00
* @throws on num > MAX_SAFE_INTEGER
*/
2016-12-02 04:23:41 -08:00
encoding.writeU64BE = function writeU64BE(dst, num, off) {
return encoding._write64(dst, num, off, true);
};
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
/**
* Write a javascript number as an int64le.
* @param {Buffer} dst
* @param {Number} num
* @param {Number} off
* @returns {Number} Buffer offset.
* @throws on num > MAX_SAFE_INTEGER
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.write64 = function write64(dst, num, off) {
return encoding._write64(dst, num, off, false);
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Write a javascript number as an int64be.
* @param {Buffer} dst
* @param {Number} num
2016-11-19 05:29:16 -08:00
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @returns {Number} Buffer offset.
2016-11-19 05:29:16 -08:00
* @throws on num > MAX_SAFE_INTEGER
*/
2016-12-02 04:23:41 -08:00
encoding.write64BE = function write64BE(dst, num, off) {
return encoding._write64(dst, num, off, true);
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Read uint64le.
2016-11-19 05:29:16 -08:00
* @param {Buffer} data
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @returns {BN}
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding.readU64BN = function readU64BN(data, off) {
2017-06-29 20:54:07 -07:00
let num = data.slice(off, off + 8);
2016-12-02 04:23:41 -08:00
return new BN(num, 'le');
};
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
/**
* Read uint64be.
* @param {Buffer} data
* @param {Number} off
* @returns {BN}
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.readU64BEBN = function readU64BEBN(data, off) {
2017-06-29 20:54:07 -07:00
let num = data.slice(off, off + 8);
2016-12-02 04:23:41 -08:00
return new BN(num, 'be');
};
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
/**
* Read int64le.
* @param {Buffer} data
* @param {Number} off
* @returns {BN}
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.read64BN = function read64BN(data, off) {
2017-06-29 20:54:07 -07:00
let num = data.slice(off, off + 8);
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
if (num[num.length - 1] & 0x80)
return new BN(num, 'le').notn(64).addn(1).neg();
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
return new BN(num, 'le');
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Read int64be.
2016-11-19 05:29:16 -08:00
* @param {Buffer} data
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @returns {BN}
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding.read64BEBN = function read64BEBN(data, off) {
2017-06-29 20:54:07 -07:00
let num = data.slice(off, off + 8);
2016-12-02 04:23:41 -08:00
if (num[0] & 0x80)
return new BN(num, 'be').notn(64).addn(1).neg();
return new BN(num, 'be');
2016-11-19 05:29:16 -08:00
};
/**
* Write int64le.
2016-12-02 04:23:41 -08:00
* @private
2016-11-19 05:29:16 -08:00
* @param {Buffer} dst
2016-12-02 04:23:41 -08:00
* @param {BN} num
2016-11-19 05:29:16 -08:00
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @param {Boolean} be
* @returns {Number} Buffer offset.
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding._write64BN = function _write64BN(dst, num, off, be) {
2017-06-29 20:54:07 -07:00
let bits = num.bitLength();
2016-11-19 05:29:16 -08:00
if (bits <= 53)
2016-12-02 04:23:41 -08:00
return encoding._write64(dst, num.toNumber(), off, be);
2016-11-19 05:29:16 -08:00
if (bits > 64)
num = num.maskn(64);
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
if (num.isNeg())
num = num.neg().inotn(64).iaddn(1);
num = num.toArray(be ? 'be' : 'le', 8);
2016-11-19 05:29:16 -08:00
2017-06-29 20:54:07 -07:00
for (let i = 0; i < num.length; i++)
2016-11-19 05:29:16 -08:00
dst[off++] = num[i];
return off;
};
/**
2016-12-02 04:23:41 -08:00
* Write uint64le.
2016-11-19 05:29:16 -08:00
* @param {Buffer} dst
2016-12-02 04:23:41 -08:00
* @param {BN} num
2016-11-19 05:29:16 -08:00
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @returns {Number} Buffer offset.
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding.writeU64BN = function writeU64BN(dst, num, off) {
return encoding._write64BN(dst, num, off, false);
};
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
/**
* Write uint64be.
* @param {Buffer} dst
* @param {BN} num
* @param {Number} off
* @returns {Number} Buffer offset.
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.writeU64BEBN = function writeU64BEBN(dst, num, off) {
return encoding._write64BN(dst, num, off, true);
};
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
/**
* Write int64le.
* @param {Buffer} dst
* @param {BN} num
* @param {Number} off
* @returns {Number} Buffer offset.
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.write64BN = function write64BN(dst, num, off) {
return encoding._write64BN(dst, num, off, false);
};
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
/**
* Write int64be.
* @param {Buffer} dst
* @param {BN} num
* @param {Number} off
* @returns {Number} Buffer offset.
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.write64BEBN = function write64BEBN(dst, num, off) {
return encoding._write64BN(dst, num, off, true);
2016-11-19 05:29:16 -08:00
};
/**
* Read a varint.
* @param {Buffer} data
* @param {Number} off
* @returns {Object}
*/
2016-12-02 04:23:41 -08:00
encoding.readVarint = function readVarint(data, off) {
2017-06-29 20:54:07 -07:00
let value, size;
2016-11-19 05:29:16 -08:00
2017-03-15 06:49:46 -07:00
assert(off < data.length, off);
2016-11-19 05:29:16 -08:00
switch (data[off]) {
case 0xff:
size = 9;
2017-03-15 06:49:46 -07:00
assert(off + size <= data.length, off);
2016-12-02 04:23:41 -08:00
value = encoding.readU64(data, off + 1);
2017-03-15 06:49:46 -07:00
enforce(value > 0xffffffff, off, 'Non-canonical varint');
2016-11-19 05:29:16 -08:00
break;
case 0xfe:
size = 5;
2017-03-15 06:49:46 -07:00
assert(off + size <= data.length, off);
2016-11-19 05:29:16 -08:00
value = data.readUInt32LE(off + 1, true);
2017-03-15 06:49:46 -07:00
enforce(value > 0xffff, off, 'Non-canonical varint');
2016-11-19 05:29:16 -08:00
break;
case 0xfd:
size = 3;
2017-03-15 06:49:46 -07:00
assert(off + size <= data.length, off);
2016-11-19 05:29:16 -08:00
value = data[off + 1] | (data[off + 2] << 8);
2017-03-15 06:49:46 -07:00
enforce(value >= 0xfd, off, 'Non-canonical varint');
2016-11-19 05:29:16 -08:00
break;
default:
size = 1;
value = data[off];
break;
}
2016-12-02 04:23:41 -08:00
return new Varint(size, value);
};
/**
* Write a varint.
* @param {Buffer} dst
* @param {Number} num
* @param {Number} off
* @returns {Number} Buffer offset.
*/
encoding.writeVarint = function writeVarint(dst, num, off) {
if (num < 0xfd) {
dst[off++] = num & 0xff;
return off;
}
if (num <= 0xffff) {
dst[off++] = 0xfd;
dst[off++] = num & 0xff;
dst[off++] = (num >> 8) & 0xff;
return off;
}
if (num <= 0xffffffff) {
dst[off++] = 0xfe;
dst[off++] = num & 0xff;
dst[off++] = (num >> 8) & 0xff;
dst[off++] = (num >> 16) & 0xff;
dst[off++] = num >>> 24;
return off;
}
dst[off++] = 0xff;
off = encoding.writeU64(dst, num, off);
return off;
2016-11-19 05:29:16 -08:00
};
2016-11-26 06:08:35 -08:00
/**
* Read a varint size.
* @param {Buffer} data
* @param {Number} off
* @returns {Number}
*/
encoding.skipVarint = function skipVarint(data, off) {
2017-03-15 06:49:46 -07:00
assert(off < data.length, off);
2016-11-26 06:08:35 -08:00
switch (data[off]) {
case 0xff:
return 9;
case 0xfe:
return 5;
case 0xfd:
return 3;
default:
return 1;
}
};
2016-11-19 05:29:16 -08:00
/**
2016-12-02 04:23:41 -08:00
* Calculate size of varint.
* @param {Number} num
* @returns {Number} size
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding.sizeVarint = function sizeVarint(num) {
if (num < 0xfd)
return 1;
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
if (num <= 0xffff)
return 3;
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
if (num <= 0xffffffff)
return 5;
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
return 9;
};
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
/**
* Read a varint.
* @param {Buffer} data
* @param {Number} off
* @returns {Object}
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.readVarintBN = function readVarintBN(data, off) {
2017-06-29 20:54:07 -07:00
let result, value, size;
2016-12-02 04:23:41 -08:00
2017-03-15 06:49:46 -07:00
assert(off < data.length, off);
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
switch (data[off]) {
case 0xff:
size = 9;
2017-03-15 06:49:46 -07:00
assert(off + size <= data.length, off);
2016-12-02 21:29:47 -08:00
value = encoding.readU64BN(data, off + 1);
2017-03-15 06:49:46 -07:00
enforce(value.bitLength() > 32, off, 'Non-canonical varint');
2016-12-02 04:23:41 -08:00
return new Varint(size, value);
default:
2016-12-08 01:17:53 -08:00
result = encoding.readVarint(data, off);
result.value = new BN(result.value);
return result;
2016-12-02 04:23:41 -08:00
}
2016-11-19 05:29:16 -08:00
};
/**
2016-12-02 04:23:41 -08:00
* Write a varint.
* @param {Buffer} dst
* @param {BN} num
* @param {Number} off
* @returns {Number} Buffer offset.
2016-11-19 05:29:16 -08:00
*/
2016-12-02 04:23:41 -08:00
encoding.writeVarintBN = function writeVarintBN(dst, num, off) {
if (num.bitLength() > 32) {
2016-12-08 01:17:53 -08:00
dst[off++] = 0xff;
off = encoding.writeU64BN(dst, num, off);
return off;
2016-11-19 05:29:16 -08:00
}
2016-12-02 04:23:41 -08:00
return encoding.writeVarint(dst, num.toNumber(), off);
};
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
/**
* Calculate size of varint.
* @param {BN} num
* @returns {Number} size
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.sizeVarintBN = function sizeVarintBN(num) {
if (num.bitLength() > 32)
return 9;
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
return encoding.sizeVarint(num.toNumber());
2016-11-19 05:29:16 -08:00
};
/**
* Read a varint (type 2).
* @param {Buffer} data
* @param {Number} off
* @returns {Object}
*/
2016-12-02 04:23:41 -08:00
encoding.readVarint2 = function readVarint2(data, off) {
2017-06-29 20:54:07 -07:00
let num = 0;
let size = 0;
let ch;
2016-11-19 05:29:16 -08:00
for (;;) {
2017-03-15 06:49:46 -07:00
assert(off < data.length, off);
2016-11-19 05:29:16 -08:00
ch = data[off++];
size++;
2017-03-15 06:49:46 -07:00
enforce(num < 0x3fffffffffff, off, 'Number exceeds 2^53-1');
2016-11-19 05:29:16 -08:00
num = (num * 0x80) + (ch & 0x7f);
2016-12-02 04:23:41 -08:00
2016-11-19 05:29:16 -08:00
if ((ch & 0x80) === 0)
break;
2016-12-02 04:23:41 -08:00
2016-11-19 05:29:16 -08:00
num++;
}
2016-12-02 04:23:41 -08:00
return new Varint(size, num);
2016-11-19 05:29:16 -08:00
};
/**
* Write a varint (type 2).
* @param {Buffer} dst
2016-12-02 04:23:41 -08:00
* @param {Number} num
2016-11-19 05:29:16 -08:00
* @param {Number} off
2016-12-02 04:23:41 -08:00
* @returns {Number} Buffer offset.
2016-11-19 05:29:16 -08:00
*/
encoding.writeVarint2 = function writeVarint2(dst, num, off) {
2017-06-29 20:54:07 -07:00
let tmp = [];
let len = 0;
2016-11-19 05:29:16 -08:00
for (;;) {
tmp[len] = (num & 0x7f) | (len ? 0x80 : 0x00);
if (num <= 0x7f)
break;
num = ((num - (num % 0x80)) / 0x80) - 1;
len++;
}
2017-03-15 06:49:46 -07:00
assert(off + len <= dst.length, off);
2016-11-19 05:29:16 -08:00
do {
dst[off++] = tmp[len];
} while (len--);
return off;
};
2016-12-02 04:23:41 -08:00
/**
* Read a varint size.
* @param {Buffer} data
* @param {Number} off
* @returns {Number}
*/
encoding.skipVarint2 = function skipVarint2(data, off) {
2017-06-29 20:54:07 -07:00
let size = 0;
let ch;
2016-12-02 04:23:41 -08:00
for (;;) {
2017-03-15 06:49:46 -07:00
assert(off < data.length, off);
2016-12-02 04:23:41 -08:00
ch = data[off++];
size++;
if ((ch & 0x80) === 0)
break;
}
return size;
};
2016-11-19 05:29:16 -08:00
/**
* Calculate size of varint (type 2).
2016-12-02 04:23:41 -08:00
* @param {Number} num
2016-11-19 05:29:16 -08:00
* @returns {Number} size
*/
encoding.sizeVarint2 = function sizeVarint2(num) {
2017-06-29 20:54:07 -07:00
let size = 0;
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
for (;;) {
size++;
if (num <= 0x7f)
break;
num = ((num - (num % 0x80)) / 0x80) - 1;
}
return size;
};
/**
* Read a varint (type 2).
* @param {Buffer} data
* @param {Number} off
* @returns {Object}
*/
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
encoding.readVarint2BN = function readVarint2BN(data, off) {
2017-06-29 20:54:07 -07:00
let num = 0;
let size = 0;
let ch;
2016-11-19 05:29:16 -08:00
2016-12-02 04:23:41 -08:00
while (num < 0x3fffffffffff) {
2017-03-15 06:49:46 -07:00
assert(off < data.length, off);
2016-12-02 04:23:41 -08:00
ch = data[off++];
size++;
num = (num * 0x80) + (ch & 0x7f);
if ((ch & 0x80) === 0)
return new Varint(size, new BN(num));
num++;
2016-11-19 05:29:16 -08:00
}
2016-12-02 04:23:41 -08:00
num = new BN(num);
2016-11-19 05:29:16 -08:00
for (;;) {
2017-03-15 06:49:46 -07:00
assert(off < data.length, off);
2016-12-02 04:23:41 -08:00
ch = data[off++];
2016-11-19 05:29:16 -08:00
size++;
2016-12-02 04:23:41 -08:00
2017-03-15 06:49:46 -07:00
enforce(num.bitLength() <= 64, off, 'Number exceeds 64 bits');
2016-12-02 04:23:41 -08:00
num.iushln(7).iaddn(ch & 0x7f);
if ((ch & 0x80) === 0)
2016-11-19 05:29:16 -08:00
break;
2016-12-02 04:23:41 -08:00
num.iaddn(1);
}
return new Varint(size, num);
};
/**
* Write a varint (type 2).
* @param {Buffer} dst
* @param {BN} num
* @param {Number} off
* @returns {Number} Buffer offset.
*/
encoding.writeVarint2BN = function writeVarint2BN(dst, num, off) {
2017-06-29 20:54:07 -07:00
let tmp = [];
let len = 0;
2016-12-02 04:23:41 -08:00
if (num.bitLength() <= 53)
return encoding.writeVarint2(dst, num.toNumber());
for (;;) {
tmp[len] = (num.words[0] & 0x7f) | (len ? 0x80 : 0x00);
if (num.cmpn(0x7f) <= 0)
break;
num.iushrn(7).isubn(1);
len++;
}
2017-03-15 06:49:46 -07:00
enforce(off + len <= dst.length, off, 'Out of bounds write');
2016-12-02 04:23:41 -08:00
do {
dst[off++] = tmp[len];
} while (len--);
return off;
};
/**
* Calculate size of varint (type 2).
* @param {BN} num
* @returns {Number} size
*/
encoding.sizeVarint2BN = function sizeVarint2BN(num) {
2017-06-29 20:54:07 -07:00
let size = 0;
2016-12-02 04:23:41 -08:00
if (num.bitLength() <= 53)
return encoding.sizeVarint(num.toNumber());
num = num.clone();
for (;;) {
size++;
if (num.cmpn(0x7f) <= 0)
break;
num.iushrn(7).isubn(1);
2016-11-19 05:29:16 -08:00
}
return size;
};
/**
* Serialize number as a u8.
* @param {Number} num
* @returns {Buffer}
*/
encoding.U8 = function U8(num) {
2017-06-29 20:54:07 -07:00
let data = Buffer.allocUnsafe(1);
data[0] = num >>> 0;
return data;
};
2016-11-19 05:29:16 -08:00
/**
* Serialize number as a u32le.
* @param {Number} num
* @returns {Buffer}
*/
encoding.U32 = function U32(num) {
2017-06-29 20:54:07 -07:00
let data = Buffer.allocUnsafe(4);
2016-11-19 05:29:16 -08:00
data.writeUInt32LE(num, 0, true);
return data;
};
2016-12-02 04:23:41 -08:00
2016-12-14 17:15:27 -08:00
/**
* Serialize number as a u32be.
* @param {Number} num
* @returns {Buffer}
*/
encoding.U32BE = function U32BE(num) {
2017-06-29 20:54:07 -07:00
let data = Buffer.allocUnsafe(4);
2016-12-14 17:15:27 -08:00
data.writeUInt32BE(num, 0, true);
return data;
};
2016-12-11 18:57:15 -08:00
/**
* Get size of varint-prefixed bytes.
* @param {Buffer} data
* @returns {Number}
*/
encoding.sizeVarBytes = function sizeVarBytes(data) {
return encoding.sizeVarint(data.length) + data.length;
};
/**
* Get size of varint-prefixed length.
* @param {Number} len
* @returns {Number}
*/
encoding.sizeVarlen = function sizeVarlen(len) {
return encoding.sizeVarint(len) + len;
};
/**
* Get size of varint-prefixed string.
* @param {String} str
* @returns {Number}
*/
encoding.sizeVarString = function sizeVarString(str, enc) {
2017-06-29 20:54:07 -07:00
let len;
2016-12-11 18:57:15 -08:00
if (typeof str !== 'string')
return encoding.sizeVarBytes(str);
len = Buffer.byteLength(str, enc);
return encoding.sizeVarint(len) + len;
};
2017-03-15 06:49:46 -07:00
/**
* EncodingError
* @constructor
* @param {Number} offset
* @param {String} reason
*/
encoding.EncodingError = function EncodingError(offset, reason) {
Error.call(this);
if (Error.captureStackTrace)
Error.captureStackTrace(this, EncodingError);
this.type = 'EncodingError';
this.message = reason + ' (offset=' + offset + ').';
};
inherits(encoding.EncodingError, Error);
2016-12-02 04:23:41 -08:00
/*
* Helpers
*/
function Varint(size, value) {
this.size = size;
this.value = value;
}
2017-03-15 06:49:46 -07:00
2017-06-29 20:54:07 -07:00
function inherits(child, parent) {
child.super_ = parent;
Object.setPrototypeOf(child.prototype, parent.prototype);
Object.defineProperty(child.prototype, 'constructor', {
value: child,
enumerable: false
});
2017-03-15 06:49:46 -07:00
}
function enforce(value, offset, reason) {
if (!value)
2017-03-15 07:21:04 -07:00
throw new encoding.EncodingError(offset, reason);
2017-03-15 06:49:46 -07:00
}
function assert(value, offset) {
if (!value)
2017-03-15 07:21:04 -07:00
throw new encoding.EncodingError(offset, 'Out of bounds read');
2017-03-15 06:49:46 -07:00
}