converters.ts 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. import { packedValue, EncodingType, FormatType } from "./custom_types";
  2. /**
  3. * Return type for all the *2packed functions
  4. */
  5. const b64Tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  6. const arraybuffer_error = "ARRAYBUFFER not supported by this environment";
  7. const uint8array_error = "UINT8ARRAY not supported by this environment";
  8. /**
  9. * Convert a string to an array of words.
  10. *
  11. * There is a known bug with an odd number of existing bytes and using a UTF-16 encoding. However, this function is
  12. * used such that the existing bytes are always a result of a previous UTF-16 str2packed call and therefore there
  13. * should never be an odd number of existing bytes.
  14. * @param str Unicode string to be converted to binary representation.
  15. * @param utfType The Unicode type to use to encode the source string.
  16. * @param existingPacked A packed int array of bytes to append the results to.
  17. * @param existingPackedLen The number of bits in `existingPacked`.
  18. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  19. * @returns Hashmap of the packed values.
  20. */
  21. function str2packed(
  22. str: string,
  23. utfType: EncodingType,
  24. existingPacked: number[] | undefined,
  25. existingPackedLen: number | undefined,
  26. bigEndianMod: -1 | 1
  27. ): packedValue {
  28. let codePnt,
  29. codePntArr,
  30. byteCnt = 0,
  31. i,
  32. j,
  33. intOffset,
  34. byteOffset,
  35. shiftModifier,
  36. transposeBytes;
  37. existingPackedLen = existingPackedLen || 0;
  38. const packed = existingPacked || [0],
  39. existingByteLen = existingPackedLen >>> 3;
  40. if ("UTF8" === utfType) {
  41. shiftModifier = bigEndianMod === -1 ? 3 : 0;
  42. for (i = 0; i < str.length; i += 1) {
  43. codePnt = str.charCodeAt(i);
  44. codePntArr = [];
  45. if (0x80 > codePnt) {
  46. codePntArr.push(codePnt);
  47. } else if (0x800 > codePnt) {
  48. codePntArr.push(0xc0 | (codePnt >>> 6));
  49. codePntArr.push(0x80 | (codePnt & 0x3f));
  50. } else if (0xd800 > codePnt || 0xe000 <= codePnt) {
  51. codePntArr.push(0xe0 | (codePnt >>> 12), 0x80 | ((codePnt >>> 6) & 0x3f), 0x80 | (codePnt & 0x3f));
  52. } else {
  53. i += 1;
  54. codePnt = 0x10000 + (((codePnt & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
  55. codePntArr.push(
  56. 0xf0 | (codePnt >>> 18),
  57. 0x80 | ((codePnt >>> 12) & 0x3f),
  58. 0x80 | ((codePnt >>> 6) & 0x3f),
  59. 0x80 | (codePnt & 0x3f)
  60. );
  61. }
  62. for (j = 0; j < codePntArr.length; j += 1) {
  63. byteOffset = byteCnt + existingByteLen;
  64. intOffset = byteOffset >>> 2;
  65. while (packed.length <= intOffset) {
  66. packed.push(0);
  67. }
  68. /* Known bug kicks in here */
  69. packed[intOffset] |= codePntArr[j] << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4)));
  70. byteCnt += 1;
  71. }
  72. }
  73. } else {
  74. /* UTF16BE or UTF16LE */
  75. shiftModifier = bigEndianMod === -1 ? 2 : 0;
  76. /* Internally strings are UTF-16BE so transpose bytes under two conditions:
  77. * need LE and not switching endianness due to SHA-3
  78. * need BE and switching endianness due to SHA-3 */
  79. transposeBytes = ("UTF16LE" === utfType && bigEndianMod !== 1) || ("UTF16LE" !== utfType && bigEndianMod === 1);
  80. for (i = 0; i < str.length; i += 1) {
  81. codePnt = str.charCodeAt(i);
  82. if (transposeBytes === true) {
  83. j = codePnt & 0xff;
  84. codePnt = (j << 8) | (codePnt >>> 8);
  85. }
  86. byteOffset = byteCnt + existingByteLen;
  87. intOffset = byteOffset >>> 2;
  88. while (packed.length <= intOffset) {
  89. packed.push(0);
  90. }
  91. packed[intOffset] |= codePnt << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4)));
  92. byteCnt += 2;
  93. }
  94. }
  95. return { value: packed, binLen: byteCnt * 8 + existingPackedLen };
  96. }
  97. /**
  98. * Convert a hex string to an array of words.
  99. *
  100. * @param str Hexadecimal string to be converted to binary representation.
  101. * @param existingPacked A packed int array of bytes to append the results to.
  102. * @param existingPackedLen The number of bits in `existingPacked` array.
  103. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  104. * @returns Hashmap of the packed values.
  105. */
  106. function hex2packed(
  107. str: string,
  108. existingPacked: number[] | undefined,
  109. existingPackedLen: number | undefined,
  110. bigEndianMod: -1 | 1
  111. ): packedValue {
  112. let i, num, intOffset, byteOffset;
  113. if (0 !== str.length % 2) {
  114. throw new Error("String of HEX type must be in byte increments");
  115. }
  116. existingPackedLen = existingPackedLen || 0;
  117. const packed = existingPacked || [0],
  118. existingByteLen = existingPackedLen >>> 3,
  119. shiftModifier = bigEndianMod === -1 ? 3 : 0;
  120. for (i = 0; i < str.length; i += 2) {
  121. num = parseInt(str.substr(i, 2), 16);
  122. if (!isNaN(num)) {
  123. byteOffset = (i >>> 1) + existingByteLen;
  124. intOffset = byteOffset >>> 2;
  125. while (packed.length <= intOffset) {
  126. packed.push(0);
  127. }
  128. packed[intOffset] |= num << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4)));
  129. } else {
  130. throw new Error("String of HEX type contains invalid characters");
  131. }
  132. }
  133. return { value: packed, binLen: str.length * 4 + existingPackedLen };
  134. }
  135. /**
  136. * Convert a string of raw bytes to an array of words.
  137. *
  138. * @param str String of raw bytes to be converted to binary representation.
  139. * @param existingPacked A packed int array of bytes to append the results to.
  140. * @param existingPackedLen The number of bits in `existingPacked` array.
  141. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  142. * @returns Hashmap of the packed values.
  143. */
  144. function bytes2packed(
  145. str: string,
  146. existingPacked: number[] | undefined,
  147. existingPackedLen: number | undefined,
  148. bigEndianMod: -1 | 1
  149. ): packedValue {
  150. let codePnt, i, intOffset, byteOffset;
  151. existingPackedLen = existingPackedLen || 0;
  152. const packed = existingPacked || [0],
  153. existingByteLen = existingPackedLen >>> 3,
  154. shiftModifier = bigEndianMod === -1 ? 3 : 0;
  155. for (i = 0; i < str.length; i += 1) {
  156. codePnt = str.charCodeAt(i);
  157. byteOffset = i + existingByteLen;
  158. intOffset = byteOffset >>> 2;
  159. if (packed.length <= intOffset) {
  160. packed.push(0);
  161. }
  162. packed[intOffset] |= codePnt << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4)));
  163. }
  164. return { value: packed, binLen: str.length * 8 + existingPackedLen };
  165. }
  166. /**
  167. * Convert a base-64 string to an array of words.
  168. *
  169. * @param str Base64-encoded string to be converted to binary representation.
  170. * @param existingPacked A packed int array of bytes to append the results to.
  171. * @param existingPackedLen The number of bits in `existingPacked` array.
  172. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  173. * @returns Hashmap of the packed values.
  174. */
  175. function b642packed(
  176. str: string,
  177. existingPacked: number[] | undefined,
  178. existingPackedLen: number | undefined,
  179. bigEndianMod: -1 | 1
  180. ): packedValue {
  181. let byteCnt = 0,
  182. index,
  183. i,
  184. j,
  185. tmpInt,
  186. strPart,
  187. intOffset,
  188. byteOffset;
  189. existingPackedLen = existingPackedLen || 0;
  190. const packed = existingPacked || [0],
  191. existingByteLen = existingPackedLen >>> 3,
  192. shiftModifier = bigEndianMod === -1 ? 3 : 0,
  193. firstEqual = str.indexOf("=");
  194. if (-1 === str.search(/^[a-zA-Z0-9=+/]+$/)) {
  195. throw new Error("Invalid character in base-64 string");
  196. }
  197. str = str.replace(/=/g, "");
  198. if (-1 !== firstEqual && firstEqual < str.length) {
  199. throw new Error("Invalid '=' found in base-64 string");
  200. }
  201. for (i = 0; i < str.length; i += 4) {
  202. strPart = str.substr(i, 4);
  203. tmpInt = 0;
  204. for (j = 0; j < strPart.length; j += 1) {
  205. index = b64Tab.indexOf(strPart.charAt(j));
  206. tmpInt |= index << (18 - 6 * j);
  207. }
  208. for (j = 0; j < strPart.length - 1; j += 1) {
  209. byteOffset = byteCnt + existingByteLen;
  210. intOffset = byteOffset >>> 2;
  211. while (packed.length <= intOffset) {
  212. packed.push(0);
  213. }
  214. packed[intOffset] |=
  215. ((tmpInt >>> (16 - j * 8)) & 0xff) << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4)));
  216. byteCnt += 1;
  217. }
  218. }
  219. return { value: packed, binLen: byteCnt * 8 + existingPackedLen };
  220. }
  221. /**
  222. * Convert an Uint8Array to an array of words.
  223. *
  224. * @param arr Uint8Array to be converted to binary representation.
  225. * @param existingPacked A packed int array of bytes to append the results to.
  226. * @param existingPackedLen The number of bits in `existingPacked` array.
  227. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  228. * @returns Hashmap of the packed values.
  229. */
  230. function uint8array2packed(
  231. arr: Uint8Array,
  232. existingPacked: number[] | undefined,
  233. existingPackedLen: number | undefined,
  234. bigEndianMod: -1 | 1
  235. ): packedValue {
  236. let i, intOffset, byteOffset;
  237. existingPackedLen = existingPackedLen || 0;
  238. const packed = existingPacked || [0],
  239. existingByteLen = existingPackedLen >>> 3,
  240. shiftModifier = bigEndianMod === -1 ? 3 : 0;
  241. for (i = 0; i < arr.length; i += 1) {
  242. byteOffset = i + existingByteLen;
  243. intOffset = byteOffset >>> 2;
  244. if (packed.length <= intOffset) {
  245. packed.push(0);
  246. }
  247. packed[intOffset] |= arr[i] << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4)));
  248. }
  249. return { value: packed, binLen: arr.length * 8 + existingPackedLen };
  250. }
  251. /**
  252. * Convert an ArrayBuffer to an array of words
  253. *
  254. * @param arr ArrayBuffer to be converted to binary representation.
  255. * @param existingPacked A packed int array of bytes to append the results to.
  256. * @param existingPackedLen The number of bits in `existingPacked` array.
  257. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  258. * @returns Hashmap of the packed values.
  259. */
  260. function arraybuffer2packed(
  261. arr: ArrayBuffer,
  262. existingPacked: number[] | undefined,
  263. existingPackedLen: number | undefined,
  264. bigEndianMod: -1 | 1
  265. ): packedValue {
  266. return uint8array2packed(new Uint8Array(arr), existingPacked, existingPackedLen, bigEndianMod);
  267. }
  268. /**
  269. * Function that takes an input format and UTF encoding and returns the appropriate function used to convert the input.
  270. *
  271. * @param format The format of the input to be converted
  272. * @param utfType The string encoding to use for TEXT inputs.
  273. * @param bigEndianMod Modifier for whether hash function is big or small endian
  274. * @returns Function that will convert an input to a packed int array.
  275. */
  276. export function getStrConverter(
  277. format: FormatType,
  278. utfType: EncodingType,
  279. bigEndianMod: -1 | 1
  280. /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
  281. ): (input: any, existingBin?: number[], existingBinLen?: number) => packedValue {
  282. /* Validate encoding */
  283. switch (utfType) {
  284. case "UTF8":
  285. /* Fallthrough */
  286. case "UTF16BE":
  287. /* Fallthrough */
  288. case "UTF16LE":
  289. /* Fallthrough */
  290. break;
  291. default:
  292. throw new Error("encoding must be UTF8, UTF16BE, or UTF16LE");
  293. }
  294. /* Map inputFormat to the appropriate converter */
  295. switch (format) {
  296. case "HEX":
  297. /**
  298. * @param str String of hexadecimal bytes to be converted to binary representation.
  299. * @param existingPacked A packed int array of bytes to append the results to.
  300. * @param existingPackedLen The number of bits in `existingPacked` array.
  301. * @returns Hashmap of the packed values.
  302. */
  303. return function (str: string, existingBin?: number[], existingBinLen?: number): packedValue {
  304. return hex2packed(str, existingBin, existingBinLen, bigEndianMod);
  305. };
  306. case "TEXT":
  307. /**
  308. * @param str Unicode string to be converted to binary representation.
  309. * @param existingPacked A packed int array of bytes to append the results to.
  310. * @param existingPackedLen The number of bits in `existingPacked` array.
  311. * @returns Hashmap of the packed values.
  312. */
  313. return function (str: string, existingBin?: number[], existingBinLen?: number): packedValue {
  314. return str2packed(str, utfType, existingBin, existingBinLen, bigEndianMod);
  315. };
  316. case "B64":
  317. /**
  318. * @param str Base64-encoded string to be converted to binary representation.
  319. * @param existingPacked A packed int array of bytes to append the results to.
  320. * @param existingPackedLen The number of bits in `existingPacked` array.
  321. * @returns Hashmap of the packed values.
  322. */
  323. return function (str: string, existingBin?: number[], existingBinLen?: number): packedValue {
  324. return b642packed(str, existingBin, existingBinLen, bigEndianMod);
  325. };
  326. case "BYTES":
  327. /**
  328. * @param str String of raw bytes to be converted to binary representation.
  329. * @param existingPacked A packed int array of bytes to append the results to.
  330. * @param existingPackedLen The number of bits in `existingPacked` array.
  331. * @returns Hashmap of the packed values.
  332. */
  333. return function (str: string, existingBin?: number[], existingBinLen?: number): packedValue {
  334. return bytes2packed(str, existingBin, existingBinLen, bigEndianMod);
  335. };
  336. case "ARRAYBUFFER":
  337. try {
  338. new ArrayBuffer(0);
  339. } catch (ignore) {
  340. throw new Error(arraybuffer_error);
  341. }
  342. /**
  343. * @param arr ArrayBuffer to be converted to binary representation.
  344. * @param existingPacked A packed int array of bytes to append the results to.
  345. * @param existingPackedLen The number of bits in `existingPacked` array.
  346. * @returns Hashmap of the packed values.
  347. */
  348. return function (arr: ArrayBuffer, existingBin?: number[], existingBinLen?: number): packedValue {
  349. return arraybuffer2packed(arr, existingBin, existingBinLen, bigEndianMod);
  350. };
  351. case "UINT8ARRAY":
  352. try {
  353. new Uint8Array(0);
  354. } catch (ignore) {
  355. throw new Error(uint8array_error);
  356. }
  357. /**
  358. * @param arr Uint8Array to be converted to binary representation.
  359. * @param existingPacked A packed int array of bytes to append the results to.
  360. * @param existingPackedLen The number of bits in `existingPacked` array.
  361. * @returns Hashmap of the packed values.
  362. */
  363. return function (arr: Uint8Array, existingBin?: number[], existingBinLen?: number): packedValue {
  364. return uint8array2packed(arr, existingBin, existingBinLen, bigEndianMod);
  365. };
  366. default:
  367. throw new Error("format must be HEX, TEXT, B64, BYTES, ARRAYBUFFER, or UINT8ARRAY");
  368. }
  369. }
  370. /**
  371. * Convert an array of words to a hexadecimal string.
  372. *
  373. * toString() won't work here because it removes preceding zeros (e.g. 0x00000001.toString === "1" rather than
  374. * "00000001" and 0.toString(16) === "0" rather than "00").
  375. *
  376. * @param packed Array of integers to be converted.
  377. * @param outputLength Length of output in bits.
  378. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  379. * @param formatOpts Hashmap containing validated output formatting options.
  380. * @returns Hexadecimal representation of `packed`.
  381. */
  382. export function packed2hex(
  383. packed: number[],
  384. outputLength: number,
  385. bigEndianMod: -1 | 1,
  386. formatOpts: { outputUpper: boolean; b64Pad: string }
  387. ): string {
  388. const hex_tab = "0123456789abcdef";
  389. let str = "",
  390. i,
  391. srcByte;
  392. const length = outputLength / 8,
  393. shiftModifier = bigEndianMod === -1 ? 3 : 0;
  394. for (i = 0; i < length; i += 1) {
  395. /* The below is more than a byte but it gets taken care of later */
  396. srcByte = packed[i >>> 2] >>> (8 * (shiftModifier + bigEndianMod * (i % 4)));
  397. str += hex_tab.charAt((srcByte >>> 4) & 0xf) + hex_tab.charAt(srcByte & 0xf);
  398. }
  399. return formatOpts["outputUpper"] ? str.toUpperCase() : str;
  400. }
  401. /**
  402. * Convert an array of words to a base-64 string.
  403. *
  404. * @param packed Array of integers to be converted.
  405. * @param outputLength Length of output in bits.
  406. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  407. * @param formatOpts Hashmap containing validated output formatting options.
  408. * @returns Base64-encoded representation of `packed`.
  409. */
  410. export function packed2b64(
  411. packed: number[],
  412. outputLength: number,
  413. bigEndianMod: -1 | 1,
  414. formatOpts: { outputUpper: boolean; b64Pad: string }
  415. ): string {
  416. let str = "",
  417. i,
  418. j,
  419. triplet,
  420. int1,
  421. int2;
  422. const length = outputLength / 8,
  423. shiftModifier = bigEndianMod === -1 ? 3 : 0;
  424. for (i = 0; i < length; i += 3) {
  425. int1 = i + 1 < length ? packed[(i + 1) >>> 2] : 0;
  426. int2 = i + 2 < length ? packed[(i + 2) >>> 2] : 0;
  427. triplet =
  428. (((packed[i >>> 2] >>> (8 * (shiftModifier + bigEndianMod * (i % 4)))) & 0xff) << 16) |
  429. (((int1 >>> (8 * (shiftModifier + bigEndianMod * ((i + 1) % 4)))) & 0xff) << 8) |
  430. ((int2 >>> (8 * (shiftModifier + bigEndianMod * ((i + 2) % 4)))) & 0xff);
  431. for (j = 0; j < 4; j += 1) {
  432. if (i * 8 + j * 6 <= outputLength) {
  433. str += b64Tab.charAt((triplet >>> (6 * (3 - j))) & 0x3f);
  434. } else {
  435. str += formatOpts["b64Pad"];
  436. }
  437. }
  438. }
  439. return str;
  440. }
  441. /**
  442. * Convert an array of words to raw bytes string.
  443. *
  444. * @param packed Array of integers to be converted.
  445. * @param outputLength Length of output in bits.
  446. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  447. * @returns Raw bytes representation of `packed`.
  448. */
  449. export function packed2bytes(packed: number[], outputLength: number, bigEndianMod: -1 | 1): string {
  450. let str = "",
  451. i,
  452. srcByte;
  453. const length = outputLength / 8,
  454. shiftModifier = bigEndianMod === -1 ? 3 : 0;
  455. for (i = 0; i < length; i += 1) {
  456. srcByte = (packed[i >>> 2] >>> (8 * (shiftModifier + bigEndianMod * (i % 4)))) & 0xff;
  457. str += String.fromCharCode(srcByte);
  458. }
  459. return str;
  460. }
  461. /**
  462. * Convert an array of words to an ArrayBuffer.
  463. *
  464. * @param packed Array of integers to be converted.
  465. * @param outputLength Length of output in bits.
  466. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  467. * @returns An ArrayBuffer containing bytes from `packed.
  468. */
  469. export function packed2arraybuffer(packed: number[], outputLength: number, bigEndianMod: -1 | 1): ArrayBuffer {
  470. let i;
  471. const length = outputLength / 8,
  472. retVal = new ArrayBuffer(length),
  473. arrView = new Uint8Array(retVal),
  474. shiftModifier = bigEndianMod === -1 ? 3 : 0;
  475. for (i = 0; i < length; i += 1) {
  476. arrView[i] = (packed[i >>> 2] >>> (8 * (shiftModifier + bigEndianMod * (i % 4)))) & 0xff;
  477. }
  478. return retVal;
  479. }
  480. /**
  481. * Convert an array of words to an Uint8Array.
  482. *
  483. * @param packed Array of integers to be converted.
  484. * @param outputLength Length of output in bits.
  485. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  486. * @returns An Uint8Array containing bytes from `packed.
  487. */
  488. export function packed2uint8array(packed: number[], outputLength: number, bigEndianMod: -1 | 1): Uint8Array {
  489. let i;
  490. const length = outputLength / 8,
  491. shiftModifier = bigEndianMod === -1 ? 3 : 0,
  492. retVal = new Uint8Array(length);
  493. for (i = 0; i < length; i += 1) {
  494. retVal[i] = (packed[i >>> 2] >>> (8 * (shiftModifier + bigEndianMod * (i % 4)))) & 0xff;
  495. }
  496. return retVal;
  497. }
  498. /**
  499. * Function that takes an output format and associated parameters and returns a function that converts packed integers
  500. * to that format.
  501. *
  502. * @param format The desired output formatting.
  503. * @param outputBinLen Output length in bits.
  504. * @param bigEndianMod Modifier for whether hash function is big or small endian.
  505. * @param outputOptions Hashmap of output formatting options
  506. * @returns Function that will convert a packed integer array to desired format.
  507. */
  508. export function getOutputConverter(
  509. format: "HEX" | "B64" | "BYTES",
  510. outputBinLen: number,
  511. bigEndianMod: -1 | 1,
  512. outputOptions: { outputUpper: boolean; b64Pad: string }
  513. ): (binarray: number[]) => string;
  514. export function getOutputConverter(
  515. format: "ARRAYBUFFER",
  516. outputBinLen: number,
  517. bigEndianMod: -1 | 1,
  518. outputOptions: { outputUpper: boolean; b64Pad: string }
  519. ): (binarray: number[]) => ArrayBuffer;
  520. export function getOutputConverter(
  521. format: "UINT8ARRAY",
  522. outputBinLen: number,
  523. bigEndianMod: -1 | 1,
  524. outputOptions: { outputUpper: boolean; b64Pad: string }
  525. ): (binarray: number[]) => Uint8Array;
  526. /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
  527. export function getOutputConverter(format: any, outputBinLen: any, bigEndianMod: any, outputOptions: any): any {
  528. switch (format) {
  529. case "HEX":
  530. return function (binarray: number[]): string {
  531. return packed2hex(binarray, outputBinLen, bigEndianMod, outputOptions);
  532. };
  533. case "B64":
  534. return function (binarray: number[]): string {
  535. return packed2b64(binarray, outputBinLen, bigEndianMod, outputOptions);
  536. };
  537. case "BYTES":
  538. return function (binarray: number[]): string {
  539. return packed2bytes(binarray, outputBinLen, bigEndianMod);
  540. };
  541. case "ARRAYBUFFER":
  542. try {
  543. /* Need to test ArrayBuffer support */
  544. new ArrayBuffer(0);
  545. } catch (ignore) {
  546. throw new Error(arraybuffer_error);
  547. }
  548. return function (binarray: number[]): ArrayBuffer {
  549. return packed2arraybuffer(binarray, outputBinLen, bigEndianMod);
  550. };
  551. case "UINT8ARRAY":
  552. try {
  553. /* Need to test Uint8Array support */
  554. new Uint8Array(0);
  555. } catch (ignore) {
  556. throw new Error(uint8array_error);
  557. }
  558. return function (binarray: number[]): Uint8Array {
  559. return packed2uint8array(binarray, outputBinLen, bigEndianMod);
  560. };
  561. default:
  562. throw new Error("format must be HEX, B64, BYTES, ARRAYBUFFER, or UINT8ARRAY");
  563. }
  564. }