84 lines
1.9 KiB
JavaScript
84 lines
1.9 KiB
JavaScript
const Variants = {
|
|
'RFC4648': {
|
|
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
|
|
padding: true,
|
|
},
|
|
'RFC4648-HEX': {
|
|
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUV',
|
|
padding: true,
|
|
},
|
|
'CROCKFORD': {
|
|
alphabet: '0123456789ABCDEFGHJKMNPQRSTVWXYZ',
|
|
padding: false,
|
|
},
|
|
};
|
|
|
|
exports.encode = (input, opts = {}) => {
|
|
const Variant = Variants[opts.variant] || Variants['RFC4648'];
|
|
const alphabet = Variant.alphabet;
|
|
const padding = opts.padding != null ? opts.padding : Variant.padding;
|
|
const data = Buffer.from(input);
|
|
|
|
let bits = 0;
|
|
let value = 0;
|
|
let output = '';
|
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
value = (value << 8) | data.readUInt8(i);
|
|
bits += 8;
|
|
|
|
while (bits >= 5) {
|
|
output += alphabet[(value >>> (bits - 5)) & 31];
|
|
bits -= 5;
|
|
}
|
|
}
|
|
|
|
if (bits > 0) {
|
|
output += alphabet[(value << (5 - bits)) & 31];
|
|
}
|
|
|
|
if (padding) {
|
|
while ((output.length % 8) !== 0) {
|
|
output += '=';
|
|
}
|
|
}
|
|
|
|
return output;
|
|
};
|
|
|
|
exports.decode = (input, opts = {}) => {
|
|
const Variant = Variants[opts.variant] || Variants['RFC4648'];
|
|
const alphabet = Variant.alphabet;
|
|
|
|
let bits = 0;
|
|
let value = 0;
|
|
|
|
if (opts.variant === 'CROCKFORD') {
|
|
input = input.toUpperCase().replace(/O/g, '0').replace(/[IL]/g, '1');
|
|
} else {
|
|
input = input.replace(/=/g, '');
|
|
}
|
|
|
|
let index = 0;
|
|
let length = input.length;
|
|
let output = Buffer.alloc(Math.ceil(length * 5 / 8));
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
let char = input[i];
|
|
let char_index = alphabet.indexOf(char);
|
|
|
|
if (char_index === -1) {
|
|
throw new Error('Invalid character: ' + char);
|
|
}
|
|
|
|
value = (value << 5) | char_index;
|
|
bits += 5;
|
|
|
|
if (bits >= 8) {
|
|
output.writeUInt8((value >>> (bits - 8)) & 255, index++);
|
|
bits -= 8;
|
|
}
|
|
}
|
|
|
|
return output;
|
|
}; |