javascriptencodingbase36

How to encode/decode a Uint8Array in Base36 in JavaScript?


I want to encode and decode Bytes from an Uint8Array (or an ArrayBuffer) to/from a string in Base36. JavaScript has the toString and parseInt functions which both support base36 but I am not sure if first converting 8 Bytes to a 64 bit floating point is the right idea.

In JS one can encode a BigInt (a number of arbitrary length) in Base36. However the other direction does not work.

How can I do this?


Solution

  • I found the solution with the help of these two posts: Why JavaScript base-36 conversion appears to be ambiguous and How to go between JS BigInts and TypedArrays

    function bigIntToBase36(num){
        return num.toString(36);
    }
    
    function base36ToBigInt(str){
        return [...str].reduce((acc,curr) => BigInt(parseInt(curr, 36)) + BigInt(36) * acc, 0n);
    }
    
    function bigIntToBuffer(bn) {
        let hex = BigInt(bn).toString(16);
        if (hex.length % 2) { hex = '0' + hex; }
    
        const len = hex.length / 2;
        const u8 = new Uint8Array(len);
    
        let i = 0;
        let j = 0;
        while (i < len) {
            u8[i] = parseInt(hex.slice(j, j+2), 16);
            i += 1;
            j += 2;
        }
    
        return u8;
    }
    
    function bufferToBigInt(buf) {
        const hex = [];
        const u8 = Uint8Array.from(buf);
    
        u8.forEach(function (i) {
            var h = i.toString(16);
            if (h.length % 2) { h = '0' + h; }
            hex.push(h);
        });
    
        return BigInt('0x' + hex.join(''));
    }
    
    const t1 = new Uint8Array([123, 51, 234, 234, 24, 124, 2, 125, 34, 255]);
    console.log(t1);
    const t2 = bigIntToBase36(bufferToBigInt(t1));
    console.log(t2);
    console.log(t2.length)
    const t3 = bigIntToBuffer(base36ToBigInt(t2));
    console.log(t3);