// Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only /* eslint-disable guard-for-in */ /* eslint-disable no-restricted-syntax */ /* eslint-disable no-proto */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { ByteBufferClass } from '../window.d'; let ByteBuffer: ByteBufferClass | undefined; const arrayBuffer = new ArrayBuffer(0); const uint8Array = new Uint8Array(); let StaticByteBufferProto: any; const StaticArrayBufferProto = (arrayBuffer as any).__proto__; const StaticUint8ArrayProto = (uint8Array as any).__proto__; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types function getString(thing: any): string { // Note: we must make this at runtime because it's loaded in the browser context if (!ByteBuffer) { ByteBuffer = new window.dcodeIO.ByteBuffer(); } if (!StaticByteBufferProto) { StaticByteBufferProto = (ByteBuffer as any).__proto__; } if (thing === Object(thing)) { if (thing.__proto__ === StaticUint8ArrayProto) { return String.fromCharCode.apply(null, thing); } if (thing.__proto__ === StaticArrayBufferProto) { return getString(new Uint8Array(thing)); } if (thing.__proto__ === StaticByteBufferProto) { return thing.toString('binary'); } } return thing; } function getStringable(thing: any): boolean { return ( typeof thing === 'string' || typeof thing === 'number' || typeof thing === 'boolean' || (thing === Object(thing) && (thing.__proto__ === StaticArrayBufferProto || thing.__proto__ === StaticUint8ArrayProto || thing.__proto__ === StaticByteBufferProto)) ); } function ensureStringed(thing: any): any { if (getStringable(thing)) { return getString(thing); } if (thing instanceof Array) { const res = []; for (let i = 0; i < thing.length; i += 1) { res[i] = ensureStringed(thing[i]); } return res; } if (thing === Object(thing)) { const res: any = {}; for (const key in thing) { res[key] = ensureStringed(thing[key]); } return res; } if (thing === null) { return null; } throw new Error(`unsure of how to jsonify object of type ${typeof thing}`); } function stringToArrayBuffer(string: string): ArrayBuffer { if (typeof string !== 'string') { throw new TypeError("'string' must be a string"); } const array = new Uint8Array(string.length); for (let i = 0; i < string.length; i += 1) { array[i] = string.charCodeAt(i); } return array.buffer; } // Number formatting utils const utils = { getString, isNumberSane: (number: string): boolean => number[0] === '+' && /^[0-9]+$/.test(number.substring(1)), // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types jsonThing: (thing: unknown) => JSON.stringify(ensureStringed(thing)), stringToArrayBuffer, unencodeNumber: (number: string): Array => number.split('.'), }; export default utils;