//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-import { dec } from './dec'
-
export const hex = Object.freeze({
- /**
- * Convert a hexadecimal string to an array of decimal byte values.
- *
- * @param {string} hex - Hexadecimal number string to convert
- * @param {number}[padding=0] - Minimum length of the resulting array padded as necessary with starting 0 values
- * @returns {number[]} Decimal array representation of the input value
- */
- toArray (hex: string, padding: number = 0): number[] {
- if (typeof hex !== 'string' || !/^[A-Fa-f0-9]+$/i.test(hex)) {
- throw new TypeError('Invalid string when converting hex to array', { cause: hex })
- }
- if (typeof padding !== 'number') {
- throw new TypeError('Invalid padding when converting hex to array', { cause: padding })
- }
- if ((hex.length & 1) !== 0) hex = `0${hex}`
- const hexArray = hex.match(/.{2}/g)
- if (hexArray == null) {
- throw new RangeError('Invalid hex string when converting to array', { cause: hexArray })
- }
- const diff = padding - hexArray.length
- const pad = new Array(diff > 0 ? diff : 0).fill(0)
- return pad.concat(hexArray.map(v => parseInt(v, 16)))
- },
-
- /**
- * Convert a hexadecimal string to a binary string.
- *
- * @param {string} hex - Hexadecimal number string to convert
- * @returns {string} Binary string representation of the input value
- */
- toBin (hex: string): string {
- return [...hex].map(c => dec.toBin(parseInt(c, 16), 4)).join('')
- },
-
/**
* Convert a hexadecimal string to an ArrayBuffer.
*
* @param {string} hex - Hexadecimal number string to convert
- * @param {number} [padding=0] - Minimum length of the resulting array padded as necessary with starting 0x00 bytes
+ * @param {number} [padding=1] - Minimum length of the resulting array padded as necessary with starting 0x00 bytes
* @returns {ArrayBuffer} Buffer representation of the input value
*/
- toBuffer (hex: string, padding: number = 0): ArrayBuffer {
+ toBuffer (hex: string, padding: number = 1): ArrayBuffer {
return this.toBytes(hex, padding).buffer
},
/**
- * Convert a hexadecimal string to a Uint8Array of bytes.
+ * Convert a hexadecimal string to a Uint8Array of bytes. The result must be
+ * at least one byte and no more than 4 GiB.
*
* @param {string} hex - Hexadecimal number string to convert
- * @param {number} [padding=0] - Minimum length of the resulting array padded as necessary with starting 0x00 bytes
+ * @param {number} [padding=1] - Minimum length of the resulting array padded as necessary with starting 0x00 bytes
* @returns {Uint8Array} Byte array representation of the input value
*/
- toBytes (hex: string, padding: number = 0): Uint8Array<ArrayBuffer> {
- return new Uint8Array(this.toArray(hex, padding))
+ toBytes (hex: string, padding: number = 1): Uint8Array<ArrayBuffer> {
+ if (typeof hex !== 'string' || !/^[0-9a-f]+$/i.test(hex)) {
+ throw new TypeError('Invalid string when converting hex to array', { cause: hex })
+ }
+ if (typeof padding !== 'number' || padding < 1 || padding > 0xffffffff) {
+ throw new TypeError('Invalid padding when converting hex to array', { cause: padding })
+ }
+ if (hex.length & 1) hex = `0${hex}`
+ const hexArray = hex.match(/.{2}/g)
+ if (hexArray == null) {
+ throw new RangeError('Invalid hex string when converting to array', { cause: hexArray })
+ }
+ const diff = padding - hexArray.length
+ const offset = diff & ~(diff >> 31)
+ const length = hexArray.length + offset
+ const bytes = new Uint8Array(length)
+ bytes.set(hex.match(/.{2}/g)?.map(b => parseInt(b, 16)) ?? [], offset)
+ return bytes
},
})