@bitblit/ratchet-common
Version:
Common tools for general use
209 lines • 7.16 kB
JavaScript
import { Logger } from '../logger/logger.js';
import { StringRatchet } from './string-ratchet.js';
import { ErrorRatchet } from './error-ratchet.js';
export class Base64Ratchet {
static safeObjectToBase64JSON(input) {
return input ? Base64Ratchet.generateBase64VersionOfString(JSON.stringify(input)) : null;
}
static safeBase64JSONParse(input) {
let rval = {};
try {
if (input) {
rval = JSON.parse(Base64Ratchet.base64StringToString(input, 'utf-8'));
}
}
catch (err) {
Logger.warn('Error parsing b64/json : %s as json, got %s', input, err, err);
rval = {};
}
return rval;
}
static generateBase64VersionOfBlob(blob) {
return new Promise(function (resolve, reject) {
if (!blob || blob.size == 0) {
reject('Wont convert null or non-blob or empty blob');
}
else {
const reader = new FileReader();
reader.onloadend = function () {
resolve(reader.result.toString());
};
reader.readAsDataURL(blob);
}
});
}
static generateBase64VersionOfString(input) {
return Base64Ratchet.generateBase64VersionOfUint8Array(StringRatchet.stringToUint8Array(input));
}
static generateBase64VersionOfUint8Array(input) {
return Base64Ratchet.uint8ArrayToBase64String(input);
}
static base64StringToUint8Array(b64encoded) {
try {
const uint8 = Base64Ratchet.base64StringToBytes(b64encoded);
return uint8;
}
catch (err) {
Logger.error('Failed to decode base64: %s', b64encoded);
throw err;
}
}
static base64StringToString(input, encoding = 'utf8') {
return new TextDecoder(encoding).decode(Base64Ratchet.base64StringToUint8Array(input));
}
static BASE64_ABC = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'+',
'/',
];
static BASE64_CODES = [
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 255, 255, 255, 0, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
];
static getBase64Code(charCode) {
if (charCode >= Base64Ratchet.BASE64_CODES.length) {
throw new Error('Unable to parse base64 string.');
}
const code = Base64Ratchet.BASE64_CODES[charCode];
if (code === 255) {
throw new Error('Unable to parse base64 string.');
}
return code;
}
static uint8ArrayToBase64UrlString(bytes) {
let tmp = Base64Ratchet.uint8ArrayToBase64String(bytes);
tmp = tmp.split('+').join('-').split('/').join('_').split('=').join('');
return tmp;
}
static uint8ArrayToBase64String(bytes) {
let result = '';
let i;
const l = bytes.length;
for (i = 2; i < l; i += 3) {
result += Base64Ratchet.BASE64_ABC[bytes[i - 2] >> 2];
result += Base64Ratchet.BASE64_ABC[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];
result += Base64Ratchet.BASE64_ABC[((bytes[i - 1] & 0x0f) << 2) | (bytes[i] >> 6)];
result += Base64Ratchet.BASE64_ABC[bytes[i] & 0x3f];
}
if (i === l + 1) {
result += Base64Ratchet.BASE64_ABC[bytes[i - 2] >> 2];
result += Base64Ratchet.BASE64_ABC[(bytes[i - 2] & 0x03) << 4];
result += '==';
}
if (i === l) {
result += Base64Ratchet.BASE64_ABC[bytes[i - 2] >> 2];
result += Base64Ratchet.BASE64_ABC[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];
result += Base64Ratchet.BASE64_ABC[(bytes[i - 1] & 0x0f) << 2];
result += '=';
}
return result;
}
static base64StringToBytes(str) {
if (str.length % 4 !== 0) {
throw ErrorRatchet.fErr('Unable to parse base64 string, length: %s', str.length);
}
const index = str.indexOf('=');
if (index !== -1 && index < str.length - 2) {
throw ErrorRatchet.fErr('Unable to parse base64 string, index %s', index);
}
const missingOctets = str.endsWith('==') ? 2 : str.endsWith('=') ? 1 : 0;
const n = str.length;
const result = new Uint8Array(new ArrayBuffer(3 * (n / 4)));
let buffer;
for (let i = 0, j = 0; i < n; i += 4, j += 3) {
buffer =
(Base64Ratchet.getBase64Code(str.charCodeAt(i)) << 18) |
(Base64Ratchet.getBase64Code(str.charCodeAt(i + 1)) << 12) |
(Base64Ratchet.getBase64Code(str.charCodeAt(i + 2)) << 6) |
Base64Ratchet.getBase64Code(str.charCodeAt(i + 3));
result[j] = buffer >> 16;
result[j + 1] = (buffer >> 8) & 0xff;
result[j + 2] = buffer & 0xff;
}
return result.subarray(0, result.length - missingOctets);
}
static base64UrlStringToBytes(str) {
let dec = str.split('-').join('+').split('_').join('/');
while (dec.length % 4 !== 0) {
dec += '=';
}
Logger.info('pre: %s post %s', str, dec);
return Base64Ratchet.base64StringToBytes(dec);
}
static encodeStringToBase64String(str, encoder = new TextEncoder()) {
return Base64Ratchet.uint8ArrayToBase64String(encoder.encode(str));
}
static encodeStringToBase64UrlString(str, encoder = new TextEncoder()) {
return Base64Ratchet.uint8ArrayToBase64UrlString(encoder.encode(str));
}
static decodeBase64StringToString(str, decoder = new TextDecoder()) {
return decoder.decode(Base64Ratchet.base64StringToBytes(str));
}
static decodeBase64UrlStringToString(str, decoder = new TextDecoder()) {
return decoder.decode(Base64Ratchet.base64UrlStringToBytes(str));
}
}
//# sourceMappingURL=base64-ratchet.js.map