Source

lib/hex2dec.ts

/**
 * A function for converting hex <-> dec w/o loss of precision.
 * By Dan Vanderkam http://www.danvk.org/hex2dec.html
 */

/**
  * Adds two arrays for the given base (10 or 16), returning the result.
  * This turns out to be the only "primitive" operation we need.
  * @param {any[]} x
  * @param {any[]} y
  * @param {number} base
  * @private
  * @return {number[]}
  */
function add(x: any[], y: any[], base: number): number[] {
    const z = [];
    const n = Math.max(x.length, y.length);
    let carry = 0;
    let i = 0;
    while(i < n || carry) {
        const xi = i < x.length ? x[i] : 0;
        const yi = i < y.length ? y[i] : 0;
        const zi = carry + xi + yi;
        z.push(zi % base);
        carry = Math.floor(zi / base);
        i++;
    }
    return z;
}

/**
 * Returns a*x, where x is an array of decimal digits and a is an ordinary
 * JavaScript number. base is the number base of the array x.
 * @param {number} num
 * @param {number[]} x
 * @param {number} base
 * @private
 * @return {number[]}
 */
function multiplyByNumber(num: number, x: number[], base: number): number[] {
    if(num < 0) return [];
    if(num == 0) return [];

    let result: number[] = [];
    let power = x;
    while(true) {
        if(num & 1) {
            result = add(result, power, base);
        }
        num = num >> 1;
        if(num === 0) break;
        power = add(power, power, base);
    }

    return result;
}

/**
 * Parses string into array of digits
 * @param {string} str to parse
 * @param {number} base
 * @private
 * @return {number[] | null}
 */
function parseToDigitsArray(str: string, base: number): number[] | null {
    const digits = str.split("");
    const ary = [];
    for(let i = digits.length - 1; i >= 0; i--) {
        const n = parseInt(digits[i], base);
        if(isNaN(n)) return null;
        ary.push(n);
    }
    return ary;
}

/**
 * Converts base
 * @param {string} str to convert
 * @param {number} fromBase
 * @param {number} toBase
 * @private
 * @return {string}
 */
function convertBase(str: string, fromBase: number, toBase: number): string | null {
    const digits = parseToDigitsArray(str, fromBase);
    if(digits === null) return null;

    let outArray: number[] = [];
    let power = [1];
    for(var i = 0; i < digits.length; i++) {
        // invariant: at this point, fromBase^i = power
        if(digits[i]) {
            outArray = add(
                outArray,
                multiplyByNumber(digits[i], power, toBase),
                toBase
            );
        }
        power = multiplyByNumber(fromBase, power, toBase);
    }

    let out = "";
    for(var i = outArray.length - 1; i >= 0; i--) {
        out += outArray[i].toString(toBase);
    }
    return out;
}

/**
 * Converts hex to decimal
 * @param {string} hexStr Hex string to convert
 * @return {string | null}
 */
function hexToDec(hexStr: string): string | null {
    if(hexStr.substring(0, 2) === "0x") hexStr = hexStr.substring(2);
    hexStr = hexStr.toLowerCase();
    return convertBase(hexStr, 16, 10);
}

export { hexToDec };