UNPKG

borc

Version:

Encode and parse data in the Concise Binary Object Representation (CBOR) data format (RFC7049).

174 lines (138 loc) 4.08 kB
'use strict' const { Buffer } = require('buffer') const Bignumber = require('bignumber.js').BigNumber const constants = require('./constants') const SHIFT32 = constants.SHIFT32 const SHIFT16 = constants.SHIFT16 const MAX_SAFE_HIGH = 0x1fffff exports.parseHalf = function parseHalf (buf) { const sign = buf[0] & 0x80 ? -1 : 1 const exp = (buf[0] & 0x7C) >> 2 const mant = ((buf[0] & 0x03) << 8) | buf[1] if (!exp) { return sign * 5.9604644775390625e-8 * mant } else if (exp === 0x1f) { return sign * (mant ? 0 / 0 : 2e308) // eslint-disable-line no-loss-of-precision } else { return sign * Math.pow(2, exp - 25) * (1024 + mant) } } function toHex (n) { if (n < 16) { return '0' + n.toString(16) } return n.toString(16) } exports.arrayBufferToBignumber = function (buf) { const len = buf.byteLength let res = '' for (let i = 0; i < len; i++) { res += toHex(buf[i]) } return new Bignumber(res, 16) } // convert an Object into a Map exports.buildMap = (obj) => { const res = new Map() const keys = Object.keys(obj) const length = keys.length for (let i = 0; i < length; i++) { res.set(keys[i], obj[keys[i]]) } return res } exports.buildInt32 = (f, g) => { return f * SHIFT16 + g } exports.buildInt64 = (f1, f2, g1, g2) => { const f = exports.buildInt32(f1, f2) const g = exports.buildInt32(g1, g2) if (f > MAX_SAFE_HIGH) { return new Bignumber(f).times(SHIFT32).plus(g) } else { return (f * SHIFT32) + g } } exports.writeHalf = function writeHalf (buf, half) { // assume 0, -0, NaN, Infinity, and -Infinity have already been caught // HACK: everyone settle in. This isn't going to be pretty. // Translate cn-cbor's C code (from Carsten Borman): // uint32_t be32; // uint16_t be16, u16; // union { // float f; // uint32_t u; // } u32; // u32.f = float_val; const u32 = Buffer.allocUnsafe(4) u32.writeFloatBE(half, 0) const u = u32.readUInt32BE(0) // if ((u32.u & 0x1FFF) == 0) { /* worth trying half */ // hildjj: If the lower 13 bits are 0, we won't lose anything in the conversion if ((u & 0x1FFF) !== 0) { return false } // int s16 = (u32.u >> 16) & 0x8000; // int exp = (u32.u >> 23) & 0xff; // int mant = u32.u & 0x7fffff; let s16 = (u >> 16) & 0x8000 // top bit is sign const exp = (u >> 23) & 0xff // then 5 bits of exponent const mant = u & 0x7fffff // if (exp == 0 && mant == 0) // ; /* 0.0, -0.0 */ // hildjj: zeros already handled. Assert if you don't believe me. // else if (exp >= 113 && exp <= 142) /* normalized */ // s16 += ((exp - 112) << 10) + (mant >> 13); if ((exp >= 113) && (exp <= 142)) { s16 += ((exp - 112) << 10) + (mant >> 13) // else if (exp >= 103 && exp < 113) { /* denorm, exp16 = 0 */ // if (mant & ((1 << (126 - exp)) - 1)) // goto float32; /* loss of precision */ // s16 += ((mant + 0x800000) >> (126 - exp)); } else if ((exp >= 103) && (exp < 113)) { if (mant & ((1 << (126 - exp)) - 1)) { return false } s16 += ((mant + 0x800000) >> (126 - exp)) // } else if (exp == 255 && mant == 0) { /* Inf */ // s16 += 0x7c00; // hildjj: Infinity already handled // } else // goto float32; /* loss of range */ } else { return false } // ensure_writable(3); // u16 = s16; // be16 = hton16p((const uint8_t*)&u16); buf.writeUInt16BE(s16, 0) return true } exports.keySorter = function (a, b) { const lenA = a[0].byteLength const lenB = b[0].byteLength if (lenA > lenB) { return 1 } if (lenB > lenA) { return -1 } return a[0].compare(b[0]) } // Adapted from http://www.2ality.com/2012/03/signedzero.html exports.isNegativeZero = (x) => { return x === 0 && (1 / x < 0) } exports.nextPowerOf2 = (n) => { let count = 0 // First n in the below condition is for // the case where n is 0 if (n && !(n & (n - 1))) { return n } while (n !== 0) { n >>= 1 count += 1 } return 1 << count }