whisper.cat/weboasis/text/base64/base64.js

387 lines
14 KiB
JavaScript
Raw Normal View History

2023-10-05 23:28:32 +11:00
'use strict';
// Async base64 encoding and decoding
// Bundles TextEncoderLite and b64.js for utf8 and typed array support.
// See: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
function asyncToBase64(value, encoding, onSuccess, onError) {
try {
switch (encoding) {
case 'ascii':
var result = window.btoa(value);
onSuccess(result);
break;
case 'utf8':
value = Base64Utils.encodeToUtf8Array(value);
// Fall through into byte array case.
case undefined:
var result = Base64Utils.uint8ToBase64(value);
onSuccess(result);
break;
default:
onError('Unknown encoding \'' + encoding + '\'.');
}
} catch (error) {
if (error.name === 'InvalidCharacterError') {
onError('Couldn\'t convert non-latin1 characters to base64.');
} else if (error.message) {
onError('Couldn\'t convert to base64 because ' + error.message + '.');
} else {
onError('Couldn\'t convert to base64 because ' + error + '.');
}
}
}
function asyncFromBase64(value, encoding, onSuccess, onError) {
try {
switch (encoding) {
case 'ascii':
var result = window.atob(Base64Utils.cleanupBase64(value));
onSuccess(result);
break;
case 'utf8':
var utf8ByteArray = Base64Utils.b64ToByteArray(Base64Utils.cleanupBase64(value));
var result = Base64Utils.decodeFromUtf8Array(utf8ByteArray);
onSuccess(result);
break;
default:
onError('Unknown encoding \'' + encoding + '\'.');
}
} catch (error) {
if (error.name == 'InvalidCharacterError') {
onError('Couldn\'t convert because the base64 decodes to non-latin1 characters.');
} else if (error.message) {
onError('Couldn\'t convert from base64 because ' + error.message + '.');
} else {
onError('Couldn\'t convert from base64 because ' + error + '.');
}
}
}
// Utility helper functions:
// cleanupBase64, uint8ToBase64, b64ToByteArray, encodeToUtf8Array, decodeFromUtf8Array
function Base64Utils() {
}
// Remove invalid characters and correct padding to accept more liberal input.
// This is modified from https://github.com/feross/buffer/blob/master/index.js by feross et. al.
Base64Utils.cleanupBase64 = function(dirty) {
// Trim whitespace.
dirty = dirty.trim ? dirty.trim() : dirty.replace(/^\s+|\s+$/g, '');
// Remove anything outside our range.
var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g;
dirty = dirty.replace(INVALID_BASE64_RE, '');
if (dirty.length < 2)
return '';
// Ensure padding is correct.
while (dirty.length % 4 !== 0)
dirty = dirty + '=';
return dirty;
}
// b64.js from https://github.com/beatgammit/base64-js by beatgammit, feross, and others.
// Modified to only export uint8ToBase64 and b64ToByteArray.
//
// The MIT License (MIT)
//
// Copyright (c) 2014
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
;(function (exports) {
var i, code, lookup, revLookup, Arr;
function initIfNeeded() {
if (code !== undefined)
return;
code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
lookup = [];
for (i = 0; i < code.length; i++)
lookup[i] = code[i];
revLookup = [];
for (i = 0; i < code.length; ++i)
revLookup[code.charCodeAt(i)] = i;
revLookup['-'.charCodeAt(0)] = 62;
revLookup['_'.charCodeAt(0)] = 63;
Arr = (typeof Uint8Array !== 'undefined') ? Uint8Array : Array;
}
function decode(elt) {
var v = revLookup[elt.charCodeAt(0)];
return v !== undefined ? v : -1;
}
function b64ToByteArray(b64) {
initIfNeeded();
var i, j, l, tmp, placeHolders, arr;
if (b64.length % 4 > 0)
throw new Error('the length is not a multiple of 4');
// the number of equal signs (place holders)
// if there are two placeholders, than the two characters before it
// represent one byte
// if there is only one, then the three characters before it represent 2 bytes
// this is just a cheap hack to not do indexOf twice
var len = b64.length;
placeHolders = b64.charAt(len - 2) === '=' ? 2 : b64.charAt(len - 1) === '=' ? 1 : 0;
// base64 is 4/3 + up to two characters of the original data
arr = new Arr(b64.length * 3 / 4 - placeHolders);
// if there are placeholders, only get up to the last complete 4 chars
l = placeHolders > 0 ? b64.length - 4 : b64.length;
var L = 0;
function push(v) {
arr[L++] = v;
}
for (i = 0, j = 0; i < l; i += 4, j += 3) {
tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3));
push((tmp & 0xFF0000) >> 16);
push((tmp & 0xFF00) >> 8);
push(tmp & 0xFF);
}
if (placeHolders === 2) {
tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4);
push(tmp & 0xFF);
} else if (placeHolders === 1) {
tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2);
push((tmp >> 8) & 0xFF);
push(tmp & 0xFF);
}
return arr;
}
function encode(num) {
return lookup[num];
}
function tripletToBase64(num) {
return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F);
}
function encodeChunk(uint8, start, end) {
var temp;
var output = [];
for (var i = start; i < end; i += 3) {
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
output.push(tripletToBase64(temp));
}
return output.join('');
}
function uint8ToBase64(uint8) {
initIfNeeded();
var i;
var extraBytes = uint8.length % 3; // if we have 1 byte left, pad 2 bytes
var output = '';
var parts = [];
var temp, length;
var maxChunkLength = 16383; // must be multiple of 3
// go through the array every three bytes, we'll deal with trailing stuff later
for (i = 0, length = uint8.length - extraBytes; i < length; i += maxChunkLength)
parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > length ? length : (i + maxChunkLength)));
// pad the end with zeros, but make sure to not forget the extra bytes
switch (extraBytes) {
case 1:
temp = uint8[uint8.length - 1];
output += encode(temp >> 2);
output += encode((temp << 4) & 0x3F);
output += '==';
break;
case 2:
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]);
output += encode(temp >> 10);
output += encode((temp >> 4) & 0x3F);
output += encode((temp << 2) & 0x3F);
output += '=';
break;
default:
break;
}
parts.push(output);
return parts.join('');
}
exports.uint8ToBase64 = uint8ToBase64;
exports.b64ToByteArray = b64ToByteArray;
}(Base64Utils));
// TextEncoderLite from https://github.com/coolaj86/TextEncoderLite/blob/master/index.js by
// coolaj86, feross, and others.
// Modified to only export encodeToUtf8Array and decodeFromUtf8Array.
//
// The MIT License (MIT)
//
// Copyright (c) Feross Aboukhadijeh, and other contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
;(function (exports) {
function utf8ToBytes(string, units) {
units = units || Infinity;
var codePoint;
var length = string.length;
var leadSurrogate = null;
var bytes = [];
for (var i = 0; i < length; i++) {
codePoint = string.charCodeAt(i);
// is surrogate component
if (codePoint > 0xD7FF && codePoint < 0xE000) {
// last char was a lead
if (leadSurrogate) {
// 2 leads in a row
if (codePoint < 0xDC00) {
if ((units -= 3) > -1)
bytes.push(0xEF, 0xBF, 0xBD);
leadSurrogate = codePoint;
continue;
} else {
// valid surrogate pair
codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000;
leadSurrogate = null;
}
} else {
// no lead yet
if (codePoint > 0xDBFF) {
// unexpected trail
if ((units -= 3) > -1)
bytes.push(0xEF, 0xBF, 0xBD);
continue;
} else if (i + 1 === length) {
// unpaired lead
if ((units -= 3) > -1)
bytes.push(0xEF, 0xBF, 0xBD);
continue;
} else {
// valid lead
leadSurrogate = codePoint;
continue;
}
}
} else if (leadSurrogate) {
// valid bmp char, but last char was a lead
if ((units -= 3) > -1)
bytes.push(0xEF, 0xBF, 0xBD);
leadSurrogate = null;
}
// encode utf8
if (codePoint < 0x80) {
if ((units -= 1) < 0)
break;
bytes.push(codePoint);
} else if (codePoint < 0x800) {
if ((units -= 2) < 0)
break;
bytes.push(
codePoint >> 0x6 | 0xC0,
codePoint & 0x3F | 0x80
);
} else if (codePoint < 0x10000) {
if ((units -= 3) < 0)
break;
bytes.push(
codePoint >> 0xC | 0xE0,
codePoint >> 0x6 & 0x3F | 0x80,
codePoint & 0x3F | 0x80
);
} else if (codePoint < 0x200000) {
if ((units -= 4) < 0)
break;
bytes.push(
codePoint >> 0x12 | 0xF0,
codePoint >> 0xC & 0x3F | 0x80,
codePoint >> 0x6 & 0x3F | 0x80,
codePoint & 0x3F | 0x80
);
} else {
throw new Error('Invalid code point');
}
}
return bytes;
}
function utf8Slice(buf, start, end) {
var res = '';
var tmp = '';
end = Math.min(buf.length, end || Infinity);
start = start || 0;
for (var i = start; i < end; i++) {
if (buf[i] <= 0x7F) {
res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i]);
tmp = '';
} else {
tmp += '%' + buf[i].toString(16);
}
}
return res + decodeUtf8Char(tmp);
}
function decodeUtf8Char(str) {
try {
return decodeURIComponent(str);
} catch (err) {
return String.fromCharCode(0xFFFD); // UTF 8 invalid char
}
}
exports.encodeToUtf8Array = function(str) {
var result;
if ('undefined' === typeof Uint8Array)
result = utf8ToBytes(str);
else
result = new Uint8Array(utf8ToBytes(str));
return result;
}
exports.decodeFromUtf8Array = function(bytes) {
return utf8Slice(bytes, 0, bytes.length);
}
}(Base64Utils));