纯JavaScript的UTF8和Base64URL编解码算法,不依赖第三方库

鉴于原生的btoa() atob() TextEncoder() TextDecoder()存在的问题,我自己动手丰衣足食,修改自一些著名的C语言实现,见以下的参考链接。

UTF-8编解码,参考:

const utf8_encoding_table = [
    { cmask: 0x80, cval: 0x00, shift: 0, lmask: 0x7F, lval: 0 },
    { cmask: 0xE0, cval: 0xC0, shift: 6, lmask: 0x7FF, lval: 0x80 },
    { cmask: 0xF0, cval: 0xE0, shift: 12, lmask: 0xFFFF, lval: 0x800 },
    { cmask: 0xF8, cval: 0xF0, shift: 18, lmask: 0x1FFFFF, lval: 0x10000 },
    { cmask: 0xFC, cval: 0xF8, shift: 24, lmask: 0x3FFFFFF, lval: 0x200000 },
    { cmask: 0xFE, cval: 0xFC, shift: 30, lmask: 0x7FFFFFFF, lval: 0x4000000 },
];

export const utf8_encode = s => {
    let chars = [...s].map(c => c.codePointAt());
    let bytes = [];
    for (let wc of chars) {
        let l = wc;
        for (let t of utf8_encoding_table) {
            if (l <= t.lmask) {
                let c = t.shift;
                bytes.push(t.cval | (l >> c));
                while (c > 0) {
                    c -= 6;
                    bytes.push(0x80 | ((l >> c) & 0x3F));
                }
                break;
            }
        }
    }
    return bytes;
};

export const utf8_decode = bytes => {
    // console.log(bytes);
    let chars = [];
    for (let s = 0; s < bytes.length; s++) {
        let n = bytes.length - s;
        let nc = 0;
        let c0 = bytes[s] & 0xFF;
        let l = c0;
        for (let t of utf8_encoding_table) {
            // console.log(l);
            nc++;
            if ((c0 & t.cmask) == t.cval) {
                l &= t.lmask;
                if (l < t.lval) break;
                chars.push(l);
                break;
            }
            if (n <= nc) break;
            s++;
            let c = (bytes[s] ^ 0x80) & 0xFF;
            if (c & 0xC0) break;
            l = (l << 6) | c;
        }
    }
    // console.log(chars);
    return String.fromCodePoint(...chars);
};

Base64编解码,参考:

const base64_encoding_table = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'];
const base64_decoding_table = {};
for (let i = 0; i < base64_encoding_table.length; i++) {
    base64_decoding_table[base64_encoding_table[i]] = i;
}

export const base64_encode = s => {
    let bytes = utf8_encode(s);
    // console.log(bytes);
    let qro = Math.ceil(bytes.length / 3);
    let rem = qro * 3 - bytes.length;
    let encoded_length = qro * 4 - rem;
    let encoded = [];
    for (let i = 0, j = 0; i < bytes.length;) {
        let octet_a = i < bytes.length ? bytes[i++] : 0;
        let octet_b = i < bytes.length ? bytes[i++] : 0;
        let octet_c = i < bytes.length ? bytes[i++] : 0;
        let triple = (octet_a << 16) + (octet_b << 8) + octet_c;
        if (j < encoded_length) encoded[j++] = base64_encoding_table[(triple >> 18) & 0x3F];
        if (j < encoded_length) encoded[j++] = base64_encoding_table[(triple >> 12) & 0x3F];
        if (j < encoded_length) encoded[j++] = base64_encoding_table[(triple >> 6) & 0x3F];
        if (j < encoded_length) encoded[j++] = base64_encoding_table[triple & 0x3F];
    }
    return encoded.join('');
};

export const base64_decode = s => {
    s = [...s];
    let qro = Math.ceil(s.length / 4);
    let rem = qro * 4 - s.length;
    if (rem == 3) {
        throw new RangeError('Encoded string length can only be integral multiples of 4 minus 1 or 2');
    }
    let byte_length = qro * 3 - rem;
    let bytes = [];
    for (let i = 0, j = 0; i < s.length;) {
        let sextet_a = i < s.length ? base64_decoding_table[s[i++]] : 0;
        let sextet_b = i < s.length ? base64_decoding_table[s[i++]] : 0;
        let sextet_c = i < s.length ? base64_decoding_table[s[i++]] : 0;
        let sextet_d = i < s.length ? base64_decoding_table[s[i++]] : 0;
        let triple = (sextet_a << 18) + (sextet_b << 12) + (sextet_c << 6) + sextet_d;
        if (j < byte_length) bytes[j++] = (triple >> 16) & 0xFF;
        if (j < byte_length) bytes[j++] = (triple >> 8) & 0xFF;
        if (j < byte_length) bytes[j++] = triple & 0xFF;
    }
    // console.log(bytes);
    return utf8_decode(bytes);
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值