import { Token, Type } from './token.js'; import { decodeErrPrefix, assertEnoughData } from './common.js'; export const uintBoundaries = [ 24, 256, 65536, 4294967296, BigInt('18446744073709551616') ]; export function readUint8(data, offset, options) { assertEnoughData(data, offset, 1); const value = data[offset]; if (options.strict === true && value < uintBoundaries[0]) { throw new Error(`${ decodeErrPrefix } integer encoded in more bytes than necessary (strict decode)`); } return value; } export function readUint16(data, offset, options) { assertEnoughData(data, offset, 2); const value = data[offset] << 8 | data[offset + 1]; if (options.strict === true && value < uintBoundaries[1]) { throw new Error(`${ decodeErrPrefix } integer encoded in more bytes than necessary (strict decode)`); } return value; } export function readUint32(data, offset, options) { assertEnoughData(data, offset, 4); const value = data[offset] * 16777216 + (data[offset + 1] << 16) + (data[offset + 2] << 8) + data[offset + 3]; if (options.strict === true && value < uintBoundaries[2]) { throw new Error(`${ decodeErrPrefix } integer encoded in more bytes than necessary (strict decode)`); } return value; } export function readUint64(data, offset, options) { assertEnoughData(data, offset, 8); const hi = data[offset] * 16777216 + (data[offset + 1] << 16) + (data[offset + 2] << 8) + data[offset + 3]; const lo = data[offset + 4] * 16777216 + (data[offset + 5] << 16) + (data[offset + 6] << 8) + data[offset + 7]; const value = (BigInt(hi) << BigInt(32)) + BigInt(lo); if (options.strict === true && value < uintBoundaries[3]) { throw new Error(`${ decodeErrPrefix } integer encoded in more bytes than necessary (strict decode)`); } if (value <= Number.MAX_SAFE_INTEGER) { return Number(value); } if (options.allowBigInt === true) { return value; } throw new Error(`${ decodeErrPrefix } integers outside of the safe integer range are not supported`); } export function decodeUint8(data, pos, _minor, options) { return new Token(Type.uint, readUint8(data, pos + 1, options), 2); } export function decodeUint16(data, pos, _minor, options) { return new Token(Type.uint, readUint16(data, pos + 1, options), 3); } export function decodeUint32(data, pos, _minor, options) { return new Token(Type.uint, readUint32(data, pos + 1, options), 5); } export function decodeUint64(data, pos, _minor, options) { return new Token(Type.uint, readUint64(data, pos + 1, options), 9); } export function encodeUint(buf, token) { return encodeUintValue(buf, 0, token.value); } export function encodeUintValue(buf, major, uint) { if (uint < uintBoundaries[0]) { const nuint = Number(uint); buf.push([major | nuint]); } else if (uint < uintBoundaries[1]) { const nuint = Number(uint); buf.push([ major | 24, nuint ]); } else if (uint < uintBoundaries[2]) { const nuint = Number(uint); buf.push([ major | 25, nuint >>> 8, nuint & 255 ]); } else if (uint < uintBoundaries[3]) { const nuint = Number(uint); buf.push([ major | 26, nuint >>> 24 & 255, nuint >>> 16 & 255, nuint >>> 8 & 255, nuint & 255 ]); } else { const buint = BigInt(uint); if (buint < uintBoundaries[4]) { const set = [ major | 27, 0, 0, 0, 0, 0, 0, 0 ]; let lo = Number(buint & BigInt(4294967295)); let hi = Number(buint >> BigInt(32) & BigInt(4294967295)); set[8] = lo & 255; lo = lo >> 8; set[7] = lo & 255; lo = lo >> 8; set[6] = lo & 255; lo = lo >> 8; set[5] = lo & 255; set[4] = hi & 255; hi = hi >> 8; set[3] = hi & 255; hi = hi >> 8; set[2] = hi & 255; hi = hi >> 8; set[1] = hi & 255; buf.push(set); } else { throw new Error(`${ decodeErrPrefix } encountered BigInt larger than allowable range`); } } } encodeUint.encodedSize = function encodedSize(token) { return encodeUintValue.encodedSize(token.value); }; encodeUintValue.encodedSize = function encodedSize(uint) { if (uint < uintBoundaries[0]) { return 1; } if (uint < uintBoundaries[1]) { return 2; } if (uint < uintBoundaries[2]) { return 3; } if (uint < uintBoundaries[3]) { return 5; } return 9; }; encodeUint.compareTokens = function compareTokens(tok1, tok2) { return tok1.value < tok2.value ? -1 : tok1.value > tok2.value ? 1 : 0; };