@ivujs/i-utils
Version:
前端模块化 JavaScript 工具库
428 lines (398 loc) • 12.7 kB
JavaScript
/*
* [hi-base64]{@link https://github.com/emn178/hi-base64}
*
* @version 0.3.1
* @author Chen, Yi-Cyuan [emn178@gmail.com]
* @copyright Chen, Yi-Cyuan 2014-2023
* @license MIT
*/
/* jslint bitwise: true */
var ENCODING_ERROR = "not a UTF-8 string";
var WINDOW = typeof window === "object";
var root = WINDOW ? window : {};
if (root.HI_BASE64_NO_WINDOW) {
WINDOW = false;
}
var WEB_WORKER = !WINDOW && typeof self === "object";
var NODE_JS = !root.HI_BASE64_NO_NODE_JS && typeof process === "object" && process.versions && process.versions.node;
if (NODE_JS) {
root = global;
} else if (WEB_WORKER) {
root = self;
}
var BASE64_ENCODE_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
var BASE64_DECODE_CHAR = {};
for (var i = 0; i < 64; ++i) {
BASE64_DECODE_CHAR[BASE64_ENCODE_CHAR[i]] = i;
}
BASE64_DECODE_CHAR["-"] = 62;
BASE64_DECODE_CHAR["_"] = 63;
var cleanBase64Str = function (base64Str) {
return base64Str.split("=")[0].replace(/[\r\n]/g, "");
};
var utf8ToBytes = function (str) {
var bytes = [];
for (var i = 0; i < str.length; i++) {
var c = str.charCodeAt(i);
if (c < 0x80) {
bytes[bytes.length] = c;
} else if (c < 0x800) {
bytes[bytes.length] = 0xc0 | (c >> 6);
bytes[bytes.length] = 0x80 | (c & 0x3f);
} else if (c < 0xd800 || c >= 0xe000) {
bytes[bytes.length] = 0xe0 | (c >> 12);
bytes[bytes.length] = 0x80 | ((c >> 6) & 0x3f);
bytes[bytes.length] = 0x80 | (c & 0x3f);
} else {
c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(++i) & 0x3ff));
bytes[bytes.length] = 0xf0 | (c >> 18);
bytes[bytes.length] = 0x80 | ((c >> 12) & 0x3f);
bytes[bytes.length] = 0x80 | ((c >> 6) & 0x3f);
bytes[bytes.length] = 0x80 | (c & 0x3f);
}
}
return bytes;
};
var decodeAsBytes = function (base64Str) {
base64Str = cleanBase64Str(base64Str);
var v1,
v2,
v3,
v4,
bytes = [],
index = 0,
length = base64Str.length;
// 4 char to 3 bytes
for (var i = 0, count = (length >> 2) << 2; i < count; ) {
v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v3 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v4 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
bytes[index++] = ((v1 << 2) | (v2 >>> 4)) & 255;
bytes[index++] = ((v2 << 4) | (v3 >>> 2)) & 255;
bytes[index++] = ((v3 << 6) | v4) & 255;
}
// remain bytes
var remain = length - count;
if (remain === 2) {
v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
bytes[index++] = ((v1 << 2) | (v2 >>> 4)) & 255;
} else if (remain === 3) {
v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v3 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
bytes[index++] = ((v1 << 2) | (v2 >>> 4)) & 255;
bytes[index++] = ((v2 << 4) | (v3 >>> 2)) & 255;
}
return bytes;
};
var encodeFromBytes = function (bytes) {
var v1,
v2,
v3,
base64Str = [],
length = bytes.length;
for (var i = 0, count = parseInt(length / 3) * 3; i < count; ) {
v1 = bytes[i++];
v2 = bytes[i++];
v3 = bytes[i++];
base64Str.push(
BASE64_ENCODE_CHAR[v1 >>> 2],
BASE64_ENCODE_CHAR[((v1 << 4) | (v2 >>> 4)) & 63],
BASE64_ENCODE_CHAR[((v2 << 2) | (v3 >>> 6)) & 63],
BASE64_ENCODE_CHAR[v3 & 63],
);
}
// remain char
var remain = length - count;
if (remain === 1) {
v1 = bytes[i];
base64Str.push(BASE64_ENCODE_CHAR[v1 >>> 2], BASE64_ENCODE_CHAR[(v1 << 4) & 63], "==");
} else if (remain === 2) {
v1 = bytes[i++];
v2 = bytes[i];
base64Str.push(
BASE64_ENCODE_CHAR[v1 >>> 2],
BASE64_ENCODE_CHAR[((v1 << 4) | (v2 >>> 4)) & 63],
BASE64_ENCODE_CHAR[(v2 << 2) & 63],
"=",
);
}
return base64Str.join("");
};
var btoa = root.btoa,
atob = root.atob,
utf8Base64Encode,
utf8Base64Decode;
if (NODE_JS) {
var Buffer = require("buffer").Buffer;
btoa = function (str) {
return Buffer.from(str, "ascii").toString("base64");
};
utf8Base64Encode = function (str) {
return Buffer.from(str).toString("base64");
};
encodeFromBytes = utf8Base64Encode;
atob = function (base64Str) {
return Buffer.from(base64Str, "base64").toString("ascii");
};
utf8Base64Decode = function (base64Str) {
return Buffer.from(base64Str, "base64").toString();
};
} else if (!btoa) {
btoa = function (str) {
var v1,
v2,
v3,
base64Str = [],
length = str.length;
for (var i = 0, count = parseInt(length / 3) * 3; i < count; ) {
v1 = str.charCodeAt(i++);
v2 = str.charCodeAt(i++);
v3 = str.charCodeAt(i++);
base64Str.push(
BASE64_ENCODE_CHAR[v1 >>> 2],
BASE64_ENCODE_CHAR[((v1 << 4) | (v2 >>> 4)) & 63],
BASE64_ENCODE_CHAR[((v2 << 2) | (v3 >>> 6)) & 63],
BASE64_ENCODE_CHAR[v3 & 63],
);
}
// remain char
var remain = length - count;
if (remain === 1) {
v1 = str.charCodeAt(i);
base64Str.push(BASE64_ENCODE_CHAR[v1 >>> 2], BASE64_ENCODE_CHAR[(v1 << 4) & 63], "==");
} else if (remain === 2) {
v1 = str.charCodeAt(i++);
v2 = str.charCodeAt(i);
base64Str.push(
BASE64_ENCODE_CHAR[v1 >>> 2],
BASE64_ENCODE_CHAR[((v1 << 4) | (v2 >>> 4)) & 63],
BASE64_ENCODE_CHAR[(v2 << 2) & 63],
"=",
);
}
return base64Str.join("");
};
utf8Base64Encode = function (str) {
var v1,
v2,
v3,
base64Str = [],
bytes = utf8ToBytes(str),
length = bytes.length;
for (var i = 0, count = parseInt(length / 3) * 3; i < count; ) {
v1 = bytes[i++];
v2 = bytes[i++];
v3 = bytes[i++];
base64Str.push(
BASE64_ENCODE_CHAR[v1 >>> 2],
BASE64_ENCODE_CHAR[((v1 << 4) | (v2 >>> 4)) & 63],
BASE64_ENCODE_CHAR[((v2 << 2) | (v3 >>> 6)) & 63],
BASE64_ENCODE_CHAR[v3 & 63],
);
}
// remain char
var remain = length - count;
if (remain === 1) {
v1 = bytes[i];
base64Str.push(BASE64_ENCODE_CHAR[v1 >>> 2], BASE64_ENCODE_CHAR[(v1 << 4) & 63], "==");
} else if (remain === 2) {
v1 = bytes[i++];
v2 = bytes[i];
base64Str.push(
BASE64_ENCODE_CHAR[v1 >>> 2],
BASE64_ENCODE_CHAR[((v1 << 4) | (v2 >>> 4)) & 63],
BASE64_ENCODE_CHAR[(v2 << 2) & 63],
"=",
);
}
return base64Str.join("");
};
atob = function (base64Str) {
var v1,
v2,
v3,
v4,
str = [],
length = base64Str.length;
// 4 char to 3 bytes
for (var i = 0, count = (length >> 2) << 2; i < count; ) {
v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v3 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v4 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
str.push(
String.fromCharCode(((v1 << 2) | (v2 >>> 4)) & 255),
String.fromCharCode(((v2 << 4) | (v3 >>> 2)) & 255),
String.fromCharCode(((v3 << 6) | v4) & 255),
);
}
// remain bytes
var remain = length - count;
if (remain === 2) {
v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
str.push(String.fromCharCode(((v1 << 2) | (v2 >>> 4)) & 255));
} else if (remain === 3) {
v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
v3 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
str.push(
String.fromCharCode(((v1 << 2) | (v2 >>> 4)) & 255),
String.fromCharCode(((v2 << 4) | (v3 >>> 2)) & 255),
);
}
return str.join("");
};
utf8Base64Decode = function (base64Str) {
var str = [],
bytes = decodeAsBytes(base64Str),
length = bytes.length;
var i = 0,
followingChars = 0,
b,
c;
while (i < length) {
b = bytes[i++];
if (b <= 0x7f) {
str.push(String.fromCharCode(b));
continue;
} else if (b > 0xbf && b <= 0xdf) {
c = b & 0x1f;
followingChars = 1;
} else if (b <= 0xef) {
c = b & 0x0f;
followingChars = 2;
} else if (b <= 0xf7) {
c = b & 0x07;
followingChars = 3;
} else {
throw new Error(ENCODING_ERROR);
}
for (var j = 0; j < followingChars; ++j) {
b = bytes[i++];
if (b < 0x80 || b > 0xbf) {
throw new Error(ENCODING_ERROR);
}
c <<= 6;
c += b & 0x3f;
}
if (c >= 0xd800 && c <= 0xdfff) {
throw new Error(ENCODING_ERROR);
}
if (c > 0x10ffff) {
throw new Error(ENCODING_ERROR);
}
if (c <= 0xffff) {
str.push(String.fromCharCode(c));
} else {
c -= 0x10000;
str.push(String.fromCharCode((c >> 10) + 0xd800), String.fromCharCode((c & 0x3ff) + 0xdc00));
}
}
return str.join("");
};
} else {
utf8Base64Encode = function (str) {
var result = [];
for (var i = 0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) {
result.push(String.fromCharCode(charcode));
} else if (charcode < 0x800) {
result.push(String.fromCharCode(0xc0 | (charcode >> 6)), String.fromCharCode(0x80 | (charcode & 0x3f)));
} else if (charcode < 0xd800 || charcode >= 0xe000) {
result.push(
String.fromCharCode(0xe0 | (charcode >> 12)),
String.fromCharCode(0x80 | ((charcode >> 6) & 0x3f)),
String.fromCharCode(0x80 | (charcode & 0x3f)),
);
} else {
charcode = 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(++i) & 0x3ff));
result.push(
String.fromCharCode(0xf0 | (charcode >> 18)),
String.fromCharCode(0x80 | ((charcode >> 12) & 0x3f)),
String.fromCharCode(0x80 | ((charcode >> 6) & 0x3f)),
String.fromCharCode(0x80 | (charcode & 0x3f)),
);
}
}
return btoa(result.join(""));
};
utf8Base64Decode = function (base64Str) {
var tmpStr = atob(base64Str.replace(/-/g, "+").replace(/_/g, "/"));
if (!/[^\x00-\x7F]/.test(tmpStr)) {
return tmpStr;
}
var str = [],
i = 0,
length = tmpStr.length,
followingChars = 0,
b,
c;
while (i < length) {
b = tmpStr.charCodeAt(i++);
if (b <= 0x7f) {
str.push(String.fromCharCode(b));
continue;
} else if (b > 0xbf && b <= 0xdf) {
c = b & 0x1f;
followingChars = 1;
} else if (b <= 0xef) {
c = b & 0x0f;
followingChars = 2;
} else if (b <= 0xf7) {
c = b & 0x07;
followingChars = 3;
} else {
throw new Error(ENCODING_ERROR);
}
for (var j = 0; j < followingChars; ++j) {
b = tmpStr.charCodeAt(i++);
if (b < 0x80 || b > 0xbf) {
throw new Error(ENCODING_ERROR);
}
c <<= 6;
c += b & 0x3f;
}
if (c >= 0xd800 && c <= 0xdfff) {
throw new Error(ENCODING_ERROR);
}
if (c > 0x10ffff) {
throw new Error(ENCODING_ERROR);
}
if (c <= 0xffff) {
str.push(String.fromCharCode(c));
} else {
c -= 0x10000;
str.push(String.fromCharCode((c >> 10) + 0xd800), String.fromCharCode((c & 0x3ff) + 0xdc00));
}
}
return str.join("");
};
}
var encode = function (str, asciiOnly) {
var notString = typeof str != "string";
if (notString && str.constructor === root.ArrayBuffer) {
str = new Uint8Array(str);
}
if (notString) {
return encodeFromBytes(str);
} else {
if (/[^\x00-\x7F]/.test(str)) {
return utf8Base64Encode(str);
} else {
return btoa(str);
}
}
};
var decode = function (base64Str, asciiOnly) {
base64Str = cleanBase64Str(base64Str);
return asciiOnly ? atob(base64Str) : utf8Base64Decode(base64Str);
};
/* 以下是内部实现需要的es模块化导出方法 */
const utf8Encode = utf8Base64Encode;
const utf8Decode = utf8Base64Decode;
export { decode, decodeAsBytes, encode, utf8Decode, utf8Encode };