UNPKG

javascript-binary-converter

Version:

A utility package to quickly handle and convert various Javascript binary objects

143 lines (98 loc) 4.96 kB
import { BytesArray, FloatConversionConfig, TypedArray } from "../sharedTypes"; import { getTwosComplementBinary, splitBinaryStringToBytes } from "./bits"; import { getSystemEndianness } from "./crossPlatform"; import { getClosestDividable, isBigInt, isFloat, normalizeBigInt } from "./number"; import { padString } from "./string"; export function integerToBinary(decimal: number | bigint) { const binary = (decimal as number >>> 0).toString(2); return binary; } export function floatToBinary(float: number, { precision = 'SINGLE' }: { precision?: 'SINGLE' | 'DOUBLE' } = {}) { const floatTypedArray = precision === 'SINGLE' ? new Float32Array([float]) : new Float64Array([float]) const int8 = new Uint8Array(floatTypedArray.buffer) const bytes = typedArrayToBytes(int8) const endianness = getSystemEndianness() return endianness === 'LITTLE' ? bytes.reverse().join("") : bytes.join("") } export function binaryToFloat(binary: string, { precision = 'SINGLE' }: FloatConversionConfig = {}) { const numBits = precision === 'SINGLE' ? 32 : 64; const numBytes = numBits/8 binary = padString(binary,numBits) const bytes = splitBinaryStringToBytes(binary) var buffer = new ArrayBuffer(numBytes); var uint8 = new Uint8Array(buffer); for (let i=0;i<bytes.length;i++) { uint8[i] = binaryToInteger(bytes[i]) } var view = new DataView(buffer); return precision === 'SINGLE' ? view.getFloat32(0, false) : view.getFloat64(0, false) } export function bigIntegerToBinary(decimal: number | bigint, nBits = BigInt(64)): string { const normalizedBigInt = normalizeBigInt(decimal, nBits) return normalizedBigInt.toString(2) } export function getBytesFromBinary(binaryString: string, { endianness = 'LITTLE' }: { endianness?: 'BIG' | 'LITTLE' } = {}) { if (binaryString.length <= 7) return [padString(binaryString)]; let closestDividableOfEight = getClosestDividable(binaryString.length, 8); const binaryStringWithAppendedZeros = padString(binaryString, closestDividableOfEight) let bytes = splitBinaryStringToBytes(binaryStringWithAppendedZeros) return endianness === 'LITTLE' ? bytes.reverse() : bytes; } export function binaryToInteger(binary: string, isSigned: boolean = false) { if (binary.length > 32) throw new Error('binaryToInteger does not support bigint') return isSigned ? getSignedInteger(binary) : parseInt(binary, 2); } export function getSignedInteger(bits: string) { const negative = (bits[0] === '1'); if (negative) { return getDecimalFromTwosComplementBinary(bits)// } else { return parseInt(bits, 2); } } export function getDecimalFromTwosComplementBinary(binary: string) { const twosComplementBinary = getTwosComplementBinary(binary) return parseInt(twosComplementBinary, 2) * -1; } export function typedArrayToBytes(typedArray: TypedArray) { const bytes: Array<string> = [] for (let decimal of typedArray) { const binary = integerToBinary(decimal); bytes.push(padString(binary, 8)) } return bytes } //relies on a string.seems to be relevant only for strings(not sure if must become generic) export function groupBytes(bytes: Array<string>, groupSize: number) { const normalizedArray: Array<string> = [] let currentBitString = "" for (let i = 1; i <= bytes.length; i++) { currentBitString += bytes[i - 1] if (i % groupSize === 0) { normalizedArray.push(currentBitString) currentBitString = "" } } return normalizedArray } export function getBytesFromInteger(decimal: number | bigint, { endianness = 'BIG' }: { endianness?: 'LITTLE' | 'BIG' } = {}) { if (typeof decimal === 'number' && isFloat(decimal)) return getBytesFromBinary(floatToBinary(decimal)) const bytes = getBytesFromBinary(isBigInt(decimal) ? bigIntegerToBinary(decimal) : integerToBinary(decimal), { endianness }) return bytes; } export function getDecimalBytesFromInteger(decimal: number | bigint, { endianness = 'BIG', isSigned = false }: { endianness?: 'LITTLE' | 'BIG', isSigned?: boolean } = {}) { const bytes = getBytesFromInteger(decimal, { endianness }) return bytes.map(byte => binaryToInteger(byte, isSigned)) } export function arrayBufferToBytes(arrayBuffer: ArrayBuffer) { const uint8 = new Uint8Array(arrayBuffer) return typedArrayToBytes(uint8) } export function bytesToIntegers(bytes: BytesArray) { return bytes.map(byte => binaryToInteger(byte)) } export function arrayBufferToDecimalBytes(arrayBuffer: ArrayBuffer, { isSigned = false }: { isSigned?: boolean } = {}) { const typedArray = isSigned ? new Int8Array(arrayBuffer) : new Uint8Array(arrayBuffer) return Array.from(typedArray) }