@thi.ng/transducers-binary
Version:
Binary data related transducers & reducers
104 lines (103 loc) • 2.63 kB
JavaScript
import { compR } from "@thi.ng/transducers/compr";
import { __iter, iterator, iterator1 } from "@thi.ng/transducers/iterator";
import { isReduced, reduced } from "@thi.ng/transducers/reduced";
const B64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const B64_SAFE = B64_CHARS.substring(0, 62) + "-_";
function base64Decode(src) {
return src ? new Uint8Array(iterator1(base64Decode(), src)) : (rfn) => {
const r = rfn[2];
let bc = 0, bs = 0;
return compR(rfn, (acc, x) => {
switch (x) {
case "-":
x = "+";
break;
case "_":
x = "/";
break;
case "=":
return reduced(acc);
default:
}
const y = B64_CHARS.indexOf(x);
bs = bc & 3 ? (bs << 6) + y : y;
if (bc++ & 3) {
acc = r(acc, 255 & bs >> (-2 * bc & 6));
}
return acc;
});
};
}
function base64Encode(...args) {
const iter = __iter(base64Encode, args, iterator);
if (iter) {
return [...iter].join("");
}
return ([init, complete, reduce]) => {
let state = 0;
let b;
const opts = { safe: false, buffer: 1024, ...args[0] };
const chars = opts.safe ? B64_SAFE : B64_CHARS;
const buf = [];
return [
init,
(acc) => {
switch (state) {
case 1:
buf.push(
chars[b >> 18 & 63],
chars[b >> 12 & 63],
"=",
"="
);
break;
case 2:
buf.push(
chars[b >> 18 & 63],
chars[b >> 12 & 63],
chars[b >> 6 & 63],
"="
);
break;
default:
}
while (buf.length && !isReduced(acc)) {
acc = reduce(acc, buf.shift());
}
return complete(acc);
},
(acc, x) => {
switch (state) {
case 0:
state = 1;
b = x << 16;
break;
case 1:
state = 2;
b += x << 8;
break;
default:
state = 0;
b += x;
buf.push(
chars[b >> 18 & 63],
chars[b >> 12 & 63],
chars[b >> 6 & 63],
chars[b & 63]
);
if (buf.length >= opts.buffer) {
for (let i = 0, n = buf.length; i < n && !isReduced(acc); i++) {
acc = reduce(acc, buf[i]);
}
buf.length = 0;
}
}
return acc;
}
];
};
}
export {
base64Decode,
base64Encode
};