@ivujs/i-utils 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -42
- package/dist/cjs/ID-card/index.cjs +21 -13
- package/dist/cjs/array/index.cjs +40 -34
- package/dist/cjs/clipboard/index.cjs +14 -10
- package/dist/cjs/color/index.cjs +73 -59
- package/dist/cjs/cookie/index.cjs +16 -13
- package/dist/cjs/crypto/base64/base64.cjs +398 -206
- package/dist/cjs/crypto/base64/index.cjs +58 -35
- package/dist/cjs/crypto/md5/index.cjs +33 -8
- package/dist/cjs/crypto/md5/md5.cjs +298 -844
- package/dist/cjs/crypto/sha256/index.cjs +95 -0
- package/dist/cjs/crypto/sha256/sha256.cjs +557 -0
- package/dist/cjs/crypto/sm3/index.cjs +27 -0
- package/dist/cjs/crypto/sm3/sm3.cjs +200 -0
- package/dist/cjs/crypto/sm4/index.cjs +101 -0
- package/dist/cjs/crypto/sm4/sm4.cjs +498 -0
- package/dist/cjs/date/index.cjs +379 -335
- package/dist/cjs/desensitized/index.cjs +21 -18
- package/dist/cjs/device/index.cjs +33 -30
- package/dist/cjs/dom/index.cjs +26 -23
- package/dist/cjs/file/index.cjs +51 -41
- package/dist/cjs/function/index.cjs +22 -19
- package/dist/cjs/id/index.cjs +6 -2
- package/dist/cjs/index.cjs +108 -127
- package/dist/cjs/keycode/index.cjs +9 -12
- package/dist/cjs/math/index.cjs +113 -81
- package/dist/cjs/number/index.cjs +10 -7
- package/dist/cjs/object/index.cjs +77 -30
- package/dist/cjs/pagination/index.cjs +25 -10
- package/dist/cjs/random/index.cjs +8 -5
- package/dist/cjs/regexp/index.cjs +23 -20
- package/dist/cjs/storage/index.cjs +4 -1
- package/dist/cjs/storage/localStorage.cjs +5 -5
- package/dist/cjs/storage/sessionStorage.cjs +6 -6
- package/dist/cjs/string/index.cjs +66 -63
- package/dist/cjs/url/index.cjs +83 -80
- package/dist/cjs/validate/index.cjs +122 -106
- package/dist/es/ID-card/index.d.ts +19 -14
- package/dist/es/ID-card/index.mjs +22 -14
- package/dist/es/array/index.d.ts +56 -50
- package/dist/es/array/index.mjs +40 -34
- package/dist/es/clipboard/index.d.ts +10 -7
- package/dist/es/clipboard/index.mjs +14 -10
- package/dist/es/color/index.d.ts +28 -25
- package/dist/es/color/index.mjs +73 -59
- package/dist/es/constants/date.d.ts +4 -174
- package/dist/es/constants/id-card.d.ts +4 -43
- package/dist/es/constants/index.d.ts +11 -7
- package/dist/es/constants/keycode.d.ts +1 -103
- package/dist/es/constants/lang.d.ts +4 -4
- package/dist/es/constants/math.d.ts +4 -4
- package/dist/es/constants/regexp.d.ts +4 -24
- package/dist/es/constants/sort.d.ts +4 -5
- package/dist/es/cookie/index.d.ts +13 -13
- package/dist/es/cookie/index.mjs +16 -13
- package/dist/es/crypto/base64/base64.d.ts +8 -5
- package/dist/es/crypto/base64/base64.mjs +393 -204
- package/dist/es/crypto/base64/index.d.ts +41 -24
- package/dist/es/crypto/base64/index.mjs +53 -32
- package/dist/es/crypto/index.d.ts +8 -8
- package/dist/es/crypto/md5/index.d.ts +20 -7
- package/dist/es/crypto/md5/index.mjs +32 -9
- package/dist/es/crypto/md5/md5.d.ts +9 -142
- package/dist/es/crypto/md5/md5.mjs +299 -844
- package/dist/es/crypto/sha256/index.d.ts +52 -0
- package/dist/es/crypto/sha256/index.mjs +86 -0
- package/dist/es/crypto/sha256/sha256.d.ts +82 -0
- package/dist/es/crypto/sha256/sha256.mjs +548 -0
- package/dist/es/crypto/sm3/index.d.ts +13 -0
- package/dist/es/crypto/sm3/index.mjs +24 -0
- package/dist/es/crypto/sm3/sm3.d.ts +3 -0
- package/dist/es/crypto/sm3/sm3.mjs +197 -0
- package/dist/es/crypto/sm4/index.d.ts +56 -0
- package/dist/es/crypto/sm4/index.mjs +95 -0
- package/dist/es/crypto/sm4/sm4.d.ts +48 -0
- package/dist/es/crypto/sm4/sm4.mjs +490 -0
- package/dist/es/date/index.d.ts +236 -175
- package/dist/es/date/index.mjs +378 -335
- package/dist/es/desensitized/index.d.ts +26 -23
- package/dist/es/desensitized/index.mjs +21 -18
- package/dist/es/device/index.d.ts +31 -25
- package/dist/es/device/index.mjs +33 -30
- package/dist/es/dom/index.d.ts +32 -29
- package/dist/es/dom/index.mjs +26 -23
- package/dist/es/file/index.d.ts +30 -30
- package/dist/es/file/index.mjs +51 -41
- package/dist/es/function/index.d.ts +10 -7
- package/dist/es/function/index.mjs +22 -19
- package/dist/es/id/index.d.ts +3 -0
- package/dist/es/id/index.mjs +6 -2
- package/dist/es/index.d.ts +24 -25
- package/dist/es/index.mjs +6 -23
- package/dist/es/keycode/index.d.ts +6 -6
- package/dist/es/keycode/index.mjs +9 -12
- package/dist/es/math/index.d.ts +37 -37
- package/dist/es/math/index.mjs +113 -81
- package/dist/es/number/index.d.ts +7 -7
- package/dist/es/number/index.mjs +10 -7
- package/dist/es/object/index.d.ts +20 -19
- package/dist/es/object/index.mjs +77 -30
- package/dist/es/pagination/index.d.ts +39 -6
- package/dist/es/pagination/index.mjs +25 -10
- package/dist/es/random/index.d.ts +10 -7
- package/dist/es/random/index.mjs +8 -5
- package/dist/es/regexp/index.d.ts +30 -30
- package/dist/es/regexp/index.mjs +23 -20
- package/dist/es/storage/index.d.ts +10 -4
- package/dist/es/storage/index.mjs +4 -1
- package/dist/es/storage/localStorage.d.ts +9 -9
- package/dist/es/storage/localStorage.mjs +5 -5
- package/dist/es/storage/sessionStorage.d.ts +9 -9
- package/dist/es/storage/sessionStorage.mjs +6 -6
- package/dist/es/string/index.d.ts +62 -59
- package/dist/es/string/index.mjs +66 -63
- package/dist/es/url/index.d.ts +65 -65
- package/dist/es/url/index.mjs +83 -80
- package/dist/es/validate/index.d.ts +83 -80
- package/dist/es/validate/index.mjs +122 -106
- package/dist/index.d.ts +2355 -2803
- package/dist/lib/index.full.umd.js +3297 -9474
- package/dist/lib/index.full.umd.min.js +2 -64
- package/dist/lib/index.full.umd.min.js.map +1 -1
- package/dist/resolver/auto-imports.cjs +38 -31
- package/dist/resolver/auto-imports.mjs +38 -31
- package/dist/resolver/index.cjs +1 -2
- package/dist/resolver/index.d.ts +1 -1
- package/dist/resolver/index.mjs +1 -2
- package/package.json +96 -90
- package/dist/cjs/crypto/aes/aes.cjs +0 -480
- package/dist/cjs/crypto/aes/index.cjs +0 -27
- package/dist/cjs/crypto/base32/base32.cjs +0 -357
- package/dist/cjs/crypto/base32/index.cjs +0 -41
- package/dist/cjs/crypto/des/des.cjs +0 -257
- package/dist/cjs/crypto/des/index.cjs +0 -28
- package/dist/cjs/crypto/sha/sha1/index.cjs +0 -24
- package/dist/cjs/crypto/sha/sha1/sha1.cjs +0 -529
- package/dist/cjs/crypto/sha/sha256/index.cjs +0 -43
- package/dist/cjs/crypto/sha/sha256/sha256.cjs +0 -595
- package/dist/cjs/crypto/sha/sha3/index.cjs +0 -41
- package/dist/cjs/crypto/sha/sha3/sha3.cjs +0 -624
- package/dist/cjs/crypto/sha/sha512/index.cjs +0 -81
- package/dist/cjs/crypto/sha/sha512/sha512.cjs +0 -950
- package/dist/cjs/crypto/sm/lib/asn1.cjs +0 -149
- package/dist/cjs/crypto/sm/lib/ec.cjs +0 -315
- package/dist/cjs/crypto/sm/lib/jsbn.cjs +0 -1608
- package/dist/cjs/crypto/sm/lib/sm3.cjs +0 -158
- package/dist/cjs/crypto/sm/lib/utils.cjs +0 -170
- package/dist/cjs/crypto/sm/sm2/index.cjs +0 -112
- package/dist/cjs/crypto/sm/sm2/sm2.cjs +0 -231
- package/dist/cjs/crypto/sm/sm3/index.cjs +0 -15
- package/dist/cjs/crypto/sm/sm3/sm3.cjs +0 -93
- package/dist/cjs/crypto/sm/sm4/index.cjs +0 -27
- package/dist/cjs/crypto/sm/sm4/sm4.cjs +0 -327
- package/dist/cjs/crypto/tea/index.cjs +0 -25
- package/dist/cjs/crypto/tea/tea.cjs +0 -187
- package/dist/cjs/weapp/index.cjs +0 -142
- package/dist/es/crypto/aes/aes.d.ts +0 -156
- package/dist/es/crypto/aes/aes.mjs +0 -478
- package/dist/es/crypto/aes/index.d.ts +0 -16
- package/dist/es/crypto/aes/index.mjs +0 -24
- package/dist/es/crypto/base32/base32.d.ts +0 -3
- package/dist/es/crypto/base32/base32.mjs +0 -353
- package/dist/es/crypto/base32/index.d.ts +0 -24
- package/dist/es/crypto/base32/index.mjs +0 -36
- package/dist/es/crypto/des/des.d.ts +0 -52
- package/dist/es/crypto/des/des.mjs +0 -255
- package/dist/es/crypto/des/index.d.ts +0 -14
- package/dist/es/crypto/des/index.mjs +0 -25
- package/dist/es/crypto/sha/index.d.ts +0 -4
- package/dist/es/crypto/sha/sha1/index.d.ts +0 -13
- package/dist/es/crypto/sha/sha1/index.mjs +0 -21
- package/dist/es/crypto/sha/sha1/sha1.d.ts +0 -2
- package/dist/es/crypto/sha/sha1/sha1.mjs +0 -526
- package/dist/es/crypto/sha/sha256/index.d.ts +0 -26
- package/dist/es/crypto/sha/sha256/index.mjs +0 -38
- package/dist/es/crypto/sha/sha256/sha256.d.ts +0 -4
- package/dist/es/crypto/sha/sha256/sha256.mjs +0 -590
- package/dist/es/crypto/sha/sha3/index.d.ts +0 -24
- package/dist/es/crypto/sha/sha3/index.mjs +0 -36
- package/dist/es/crypto/sha/sha3/sha3.d.ts +0 -4
- package/dist/es/crypto/sha/sha3/sha3.mjs +0 -619
- package/dist/es/crypto/sha/sha512/index.d.ts +0 -52
- package/dist/es/crypto/sha/sha512/index.mjs +0 -72
- package/dist/es/crypto/sha/sha512/sha512.d.ts +0 -8
- package/dist/es/crypto/sha/sha512/sha512.mjs +0 -941
- package/dist/es/crypto/sm/index.d.ts +0 -3
- package/dist/es/crypto/sm/lib/asn1.d.ts +0 -12
- package/dist/es/crypto/sm/lib/asn1.mjs +0 -146
- package/dist/es/crypto/sm/lib/ec.d.ts +0 -126
- package/dist/es/crypto/sm/lib/ec.mjs +0 -312
- package/dist/es/crypto/sm/lib/jsbn.d.ts +0 -198
- package/dist/es/crypto/sm/lib/jsbn.mjs +0 -1605
- package/dist/es/crypto/sm/lib/sm3.d.ts +0 -5
- package/dist/es/crypto/sm/lib/sm3.mjs +0 -155
- package/dist/es/crypto/sm/lib/utils.d.ts +0 -53
- package/dist/es/crypto/sm/lib/utils.mjs +0 -158
- package/dist/es/crypto/sm/sm2/index.d.ts +0 -71
- package/dist/es/crypto/sm/sm2/index.mjs +0 -101
- package/dist/es/crypto/sm/sm2/sm2.d.ts +0 -34
- package/dist/es/crypto/sm/sm2/sm2.mjs +0 -220
- package/dist/es/crypto/sm/sm3/index.d.ts +0 -7
- package/dist/es/crypto/sm/sm3/index.mjs +0 -13
- package/dist/es/crypto/sm/sm3/sm3.d.ts +0 -1
- package/dist/es/crypto/sm/sm3/sm3.mjs +0 -91
- package/dist/es/crypto/sm/sm4/index.d.ts +0 -16
- package/dist/es/crypto/sm/sm4/index.mjs +0 -24
- package/dist/es/crypto/sm/sm4/sm4.d.ts +0 -2
- package/dist/es/crypto/sm/sm4/sm4.mjs +0 -324
- package/dist/es/crypto/tea/index.d.ts +0 -14
- package/dist/es/crypto/tea/index.mjs +0 -22
- package/dist/es/crypto/tea/tea.d.ts +0 -69
- package/dist/es/crypto/tea/tea.mjs +0 -185
- package/dist/es/weapp/index.d.ts +0 -57
- package/dist/es/weapp/index.mjs +0 -131
|
@@ -1,209 +1,273 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @version 0.3.1
|
|
7
|
-
* @author Chen, Yi-Cyuan [emn178@gmail.com]
|
|
8
|
-
* @copyright Chen, Yi-Cyuan 2014-2023
|
|
9
|
-
* @license MIT
|
|
4
|
+
* base64加解密
|
|
5
|
+
* 高性能、高健壮性、纯JS实现,兼容Node/浏览器/Worker
|
|
10
6
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
WINDOW = false;
|
|
17
|
-
}
|
|
18
|
-
var WEB_WORKER = !WINDOW && typeof self === "object";
|
|
19
|
-
var NODE_JS = !root.HI_BASE64_NO_NODE_JS && typeof process === "object" && process.versions && process.versions.node;
|
|
20
|
-
if (NODE_JS) {
|
|
21
|
-
root = global;
|
|
22
|
-
}
|
|
23
|
-
else if (WEB_WORKER) {
|
|
24
|
-
root = self;
|
|
25
|
-
}
|
|
26
|
-
var BASE64_ENCODE_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
|
|
27
|
-
var BASE64_DECODE_CHAR = {};
|
|
28
|
-
for (var i = 0; i < 64; ++i) {
|
|
7
|
+
// 核心常量定义
|
|
8
|
+
const ENCODING_ERROR = "not a UTF-8 string";
|
|
9
|
+
const BASE64_ENCODE_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
|
|
10
|
+
const BASE64_DECODE_CHAR = {};
|
|
11
|
+
for (let i = 0; i < 64; ++i) {
|
|
29
12
|
BASE64_DECODE_CHAR[BASE64_ENCODE_CHAR[i]] = i;
|
|
30
13
|
}
|
|
14
|
+
// 兼容URL安全的Base64
|
|
31
15
|
BASE64_DECODE_CHAR["-"] = 62;
|
|
32
16
|
BASE64_DECODE_CHAR["_"] = 63;
|
|
33
|
-
|
|
34
|
-
|
|
17
|
+
// ======================== 精简版环境判断(核心场景全覆盖,保留!)========================
|
|
18
|
+
const isNodeEnv = typeof process === "object" && process.versions && process.versions.node;
|
|
19
|
+
const isBrowserEnv = typeof window === "object" && typeof window.btoa === "function";
|
|
20
|
+
const root = isNodeEnv ? global : typeof self === "object" ? self : window;
|
|
21
|
+
// ======================== 核心工具函数(全部保留,原生API更快!)========================
|
|
22
|
+
/**
|
|
23
|
+
* 清理Base64字符串(移除等号、换行符、非法字符)
|
|
24
|
+
*/
|
|
25
|
+
const cleanBase64Str = function (base64Str) {
|
|
26
|
+
return base64Str
|
|
27
|
+
.split("=")[0]
|
|
28
|
+
.replace(/[\r\n]/g, "")
|
|
29
|
+
.replace(/[^A-Za-z0-9+/=_-]/g, ""); // 过滤非法字符
|
|
35
30
|
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
/**
|
|
32
|
+
* UTF-8字符串转字节数组(性能优化版)
|
|
33
|
+
*/
|
|
34
|
+
const utf8ToBytes = function (str) {
|
|
35
|
+
const len = str.length; // 缓存长度,减少属性访问
|
|
36
|
+
const bytes = new Array(len * 4); // 预分配最大可能长度(避免频繁扩容)
|
|
37
|
+
let byteIndex = 0;
|
|
38
|
+
for (let i = 0; i < len; i++) {
|
|
39
|
+
const c = str.charCodeAt(i);
|
|
40
40
|
if (c < 0x80) {
|
|
41
|
-
bytes[
|
|
41
|
+
bytes[byteIndex++] = c;
|
|
42
42
|
}
|
|
43
43
|
else if (c < 0x800) {
|
|
44
|
-
bytes[
|
|
45
|
-
bytes[
|
|
44
|
+
bytes[byteIndex++] = 0xc0 | (c >> 6);
|
|
45
|
+
bytes[byteIndex++] = 0x80 | (c & 0x3f);
|
|
46
46
|
}
|
|
47
47
|
else if (c < 0xd800 || c >= 0xe000) {
|
|
48
|
-
bytes[
|
|
49
|
-
bytes[
|
|
50
|
-
bytes[
|
|
48
|
+
bytes[byteIndex++] = 0xe0 | (c >> 12);
|
|
49
|
+
bytes[byteIndex++] = 0x80 | ((c >> 6) & 0x3f);
|
|
50
|
+
bytes[byteIndex++] = 0x80 | (c & 0x3f);
|
|
51
51
|
}
|
|
52
52
|
else {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
bytes[
|
|
56
|
-
bytes[
|
|
57
|
-
bytes[
|
|
53
|
+
// 处理代理对
|
|
54
|
+
const code = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(++i) & 0x3ff));
|
|
55
|
+
bytes[byteIndex++] = 0xf0 | (code >> 18);
|
|
56
|
+
bytes[byteIndex++] = 0x80 | ((code >> 12) & 0x3f);
|
|
57
|
+
bytes[byteIndex++] = 0x80 | ((code >> 6) & 0x3f);
|
|
58
|
+
bytes[byteIndex++] = 0x80 | (code & 0x3f);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
+
// 截断数组到实际长度
|
|
62
|
+
return bytes.slice(0, byteIndex);
|
|
61
63
|
};
|
|
62
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Base64字符串解码为字节数组(性能优化版)
|
|
66
|
+
*/
|
|
67
|
+
const decodeAsBytes = function (base64Str) {
|
|
68
|
+
// 空值快速返回
|
|
69
|
+
if (!base64Str)
|
|
70
|
+
return [];
|
|
63
71
|
base64Str = cleanBase64Str(base64Str);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
const len = base64Str.length;
|
|
73
|
+
const count = (len >> 2) << 2;
|
|
74
|
+
// 预计算最大长度:3/4 * 总字符数,减少数组扩容
|
|
75
|
+
const bytes = new Array(Math.floor((len * 3) / 4));
|
|
76
|
+
let byteIndex = 0;
|
|
77
|
+
let i = 0; // 把i的作用域提升到函数级,确保后续能访问
|
|
78
|
+
// 4字符转3字节
|
|
79
|
+
for (; i < count;) {
|
|
80
|
+
const v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)] || 0;
|
|
81
|
+
const v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)] || 0;
|
|
82
|
+
const v3 = BASE64_DECODE_CHAR[base64Str.charAt(i++)] || 0;
|
|
83
|
+
const v4 = BASE64_DECODE_CHAR[base64Str.charAt(i++)] || 0;
|
|
84
|
+
bytes[byteIndex++] = ((v1 << 2) | (v2 >>> 4)) & 255;
|
|
85
|
+
bytes[byteIndex++] = ((v2 << 4) | (v3 >>> 2)) & 255;
|
|
86
|
+
bytes[byteIndex++] = ((v3 << 6) | v4) & 255;
|
|
74
87
|
}
|
|
75
|
-
//
|
|
76
|
-
|
|
88
|
+
// 处理剩余字符(此时i的作用域有效)
|
|
89
|
+
const remain = len - count;
|
|
77
90
|
if (remain === 2) {
|
|
78
|
-
v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
|
|
79
|
-
v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
|
|
80
|
-
bytes[
|
|
91
|
+
const v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)] || 0;
|
|
92
|
+
const v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)] || 0;
|
|
93
|
+
bytes[byteIndex++] = ((v1 << 2) | (v2 >>> 4)) & 255;
|
|
81
94
|
}
|
|
82
95
|
else if (remain === 3) {
|
|
83
|
-
v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
|
|
84
|
-
v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
|
|
85
|
-
v3 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
|
|
86
|
-
bytes[
|
|
87
|
-
bytes[
|
|
96
|
+
const v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)] || 0;
|
|
97
|
+
const v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)] || 0;
|
|
98
|
+
const v3 = BASE64_DECODE_CHAR[base64Str.charAt(i++)] || 0;
|
|
99
|
+
bytes[byteIndex++] = ((v1 << 2) | (v2 >>> 4)) & 255;
|
|
100
|
+
bytes[byteIndex++] = ((v2 << 4) | (v3 >>> 2)) & 255;
|
|
88
101
|
}
|
|
89
|
-
|
|
102
|
+
// 截断数组到实际长度
|
|
103
|
+
return bytes.slice(0, byteIndex);
|
|
90
104
|
};
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
/**
|
|
106
|
+
* 抽离公共逻辑:字节数组转Base64字符(减少代码冗余)
|
|
107
|
+
*/
|
|
108
|
+
const bytesToBase64Chars = function (bytes) {
|
|
109
|
+
const len = bytes.length;
|
|
110
|
+
const count = Math.floor(len / 3) * 3;
|
|
111
|
+
const base64Str = new Array(Math.ceil((len * 4) / 3)); // 预分配长度
|
|
112
|
+
let strIndex = 0;
|
|
113
|
+
// 3字节转4字符
|
|
114
|
+
for (let i = 0; i < count;) {
|
|
115
|
+
const v1 = bytes[i++];
|
|
116
|
+
const v2 = bytes[i++];
|
|
117
|
+
const v3 = bytes[i++];
|
|
118
|
+
base64Str[strIndex++] = BASE64_ENCODE_CHAR[v1 >>> 2];
|
|
119
|
+
base64Str[strIndex++] = BASE64_ENCODE_CHAR[((v1 << 4) | (v2 >>> 4)) & 63];
|
|
120
|
+
base64Str[strIndex++] = BASE64_ENCODE_CHAR[((v2 << 2) | (v3 >>> 6)) & 63];
|
|
121
|
+
base64Str[strIndex++] = BASE64_ENCODE_CHAR[v3 & 63];
|
|
98
122
|
}
|
|
99
|
-
//
|
|
100
|
-
|
|
123
|
+
// 处理剩余字节
|
|
124
|
+
const remain = len - count;
|
|
101
125
|
if (remain === 1) {
|
|
102
|
-
v1 = bytes[
|
|
103
|
-
base64Str
|
|
126
|
+
const v1 = bytes[count];
|
|
127
|
+
base64Str[strIndex++] = BASE64_ENCODE_CHAR[v1 >>> 2];
|
|
128
|
+
base64Str[strIndex++] = BASE64_ENCODE_CHAR[(v1 << 4) & 63];
|
|
129
|
+
base64Str[strIndex++] = "=";
|
|
130
|
+
base64Str[strIndex++] = "=";
|
|
104
131
|
}
|
|
105
132
|
else if (remain === 2) {
|
|
106
|
-
v1 = bytes[
|
|
107
|
-
v2 = bytes[
|
|
108
|
-
base64Str
|
|
133
|
+
const v1 = bytes[count];
|
|
134
|
+
const v2 = bytes[count + 1];
|
|
135
|
+
base64Str[strIndex++] = BASE64_ENCODE_CHAR[v1 >>> 2];
|
|
136
|
+
base64Str[strIndex++] = BASE64_ENCODE_CHAR[((v1 << 4) | (v2 >>> 4)) & 63];
|
|
137
|
+
base64Str[strIndex++] = BASE64_ENCODE_CHAR[(v2 << 2) & 63];
|
|
138
|
+
base64Str[strIndex++] = "=";
|
|
109
139
|
}
|
|
110
140
|
return base64Str.join("");
|
|
111
141
|
};
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
142
|
+
/**
|
|
143
|
+
* 字节数组编码为Base64字符串(复用公共逻辑)
|
|
144
|
+
*/
|
|
145
|
+
let encodeFromBytes = function (bytes) {
|
|
146
|
+
// 空值快速返回
|
|
147
|
+
if (!bytes || bytes.length === 0)
|
|
148
|
+
return "";
|
|
149
|
+
return bytesToBase64Chars(bytes);
|
|
150
|
+
};
|
|
151
|
+
// ======================== 环境适配的btoa/atob实现(全部保留,原生更快!)=======================
|
|
152
|
+
let btoa = root.btoa;
|
|
153
|
+
let atob = root.atob;
|
|
154
|
+
let utf8Base64Encode;
|
|
155
|
+
let utf8Base64Decode;
|
|
156
|
+
// 1. Node.js环境(纯JS实现,不使用require)
|
|
157
|
+
if (isNodeEnv) {
|
|
158
|
+
// 纯JS版btoa(替代Buffer实现)
|
|
115
159
|
btoa = function (str) {
|
|
116
|
-
|
|
160
|
+
if (!str)
|
|
161
|
+
return "";
|
|
162
|
+
const bytes = Array.from(str).map((c) => c.charCodeAt(0));
|
|
163
|
+
return bytesToBase64Chars(bytes);
|
|
117
164
|
};
|
|
118
|
-
|
|
119
|
-
return Buffer.from(str).toString("base64");
|
|
120
|
-
};
|
|
121
|
-
encodeFromBytes = utf8Base64Encode;
|
|
165
|
+
// 纯JS版atob
|
|
122
166
|
atob = function (base64Str) {
|
|
123
|
-
|
|
167
|
+
if (!base64Str)
|
|
168
|
+
return "";
|
|
169
|
+
const bytes = decodeAsBytes(base64Str);
|
|
170
|
+
return String.fromCharCode.apply(null, bytes);
|
|
171
|
+
};
|
|
172
|
+
// 纯JS版UTF8编码/解码(和浏览器环境保持一致)
|
|
173
|
+
utf8Base64Encode = function (str) {
|
|
174
|
+
if (!str)
|
|
175
|
+
return "";
|
|
176
|
+
const bytes = utf8ToBytes(str);
|
|
177
|
+
return bytesToBase64Chars(bytes);
|
|
124
178
|
};
|
|
125
179
|
utf8Base64Decode = function (base64Str) {
|
|
126
|
-
|
|
180
|
+
if (!base64Str)
|
|
181
|
+
return "";
|
|
182
|
+
const bytes = decodeAsBytes(base64Str);
|
|
183
|
+
const str = [];
|
|
184
|
+
const len = bytes.length;
|
|
185
|
+
let i = 0;
|
|
186
|
+
while (i < len) {
|
|
187
|
+
const b = bytes[i++];
|
|
188
|
+
if (b <= 0x7f) {
|
|
189
|
+
str.push(String.fromCharCode(b));
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
let c, followingChars;
|
|
193
|
+
if (b > 0xbf && b <= 0xdf) {
|
|
194
|
+
c = b & 0x1f;
|
|
195
|
+
followingChars = 1;
|
|
196
|
+
}
|
|
197
|
+
else if (b <= 0xef) {
|
|
198
|
+
c = b & 0x0f;
|
|
199
|
+
followingChars = 2;
|
|
200
|
+
}
|
|
201
|
+
else if (b <= 0xf7) {
|
|
202
|
+
c = b & 0x07;
|
|
203
|
+
followingChars = 3;
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
throw new Error(ENCODING_ERROR);
|
|
207
|
+
}
|
|
208
|
+
// 校验后续字节合法性
|
|
209
|
+
for (let j = 0; j < followingChars; ++j) {
|
|
210
|
+
const byte = bytes[i++];
|
|
211
|
+
if (i > len || byte < 0x80 || byte > 0xbf) {
|
|
212
|
+
throw new Error(ENCODING_ERROR);
|
|
213
|
+
}
|
|
214
|
+
c = (c << 6) + (byte & 0x3f);
|
|
215
|
+
}
|
|
216
|
+
// 校验Unicode范围
|
|
217
|
+
if (c >= 0xd800 && c <= 0xdfff)
|
|
218
|
+
throw new Error(ENCODING_ERROR);
|
|
219
|
+
if (c > 0x10ffff)
|
|
220
|
+
throw new Error(ENCODING_ERROR);
|
|
221
|
+
// 转换为字符
|
|
222
|
+
if (c <= 0xffff) {
|
|
223
|
+
str.push(String.fromCharCode(c));
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
c -= 0x10000;
|
|
227
|
+
str.push(String.fromCharCode((c >> 10) + 0xd800), String.fromCharCode((c & 0x3ff) + 0xdc00));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return str.join("");
|
|
127
231
|
};
|
|
232
|
+
// 2. 无原生btoa/atob的环境(老旧浏览器/Worker)
|
|
128
233
|
}
|
|
129
|
-
else if (!
|
|
234
|
+
else if (!isBrowserEnv) {
|
|
235
|
+
// 纯JS版btoa(复用公共逻辑)
|
|
130
236
|
btoa = function (str) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
v3 = str.charCodeAt(i++);
|
|
136
|
-
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]);
|
|
137
|
-
}
|
|
138
|
-
// remain char
|
|
139
|
-
var remain = length - count;
|
|
140
|
-
if (remain === 1) {
|
|
141
|
-
v1 = str.charCodeAt(i);
|
|
142
|
-
base64Str.push(BASE64_ENCODE_CHAR[v1 >>> 2], BASE64_ENCODE_CHAR[(v1 << 4) & 63], "==");
|
|
143
|
-
}
|
|
144
|
-
else if (remain === 2) {
|
|
145
|
-
v1 = str.charCodeAt(i++);
|
|
146
|
-
v2 = str.charCodeAt(i);
|
|
147
|
-
base64Str.push(BASE64_ENCODE_CHAR[v1 >>> 2], BASE64_ENCODE_CHAR[((v1 << 4) | (v2 >>> 4)) & 63], BASE64_ENCODE_CHAR[(v2 << 2) & 63], "=");
|
|
148
|
-
}
|
|
149
|
-
return base64Str.join("");
|
|
150
|
-
};
|
|
151
|
-
utf8Base64Encode = function (str) {
|
|
152
|
-
var v1, v2, v3, base64Str = [], bytes = utf8ToBytes(str), length = bytes.length;
|
|
153
|
-
for (var i = 0, count = parseInt(length / 3) * 3; i < count;) {
|
|
154
|
-
v1 = bytes[i++];
|
|
155
|
-
v2 = bytes[i++];
|
|
156
|
-
v3 = bytes[i++];
|
|
157
|
-
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]);
|
|
158
|
-
}
|
|
159
|
-
// remain char
|
|
160
|
-
var remain = length - count;
|
|
161
|
-
if (remain === 1) {
|
|
162
|
-
v1 = bytes[i];
|
|
163
|
-
base64Str.push(BASE64_ENCODE_CHAR[v1 >>> 2], BASE64_ENCODE_CHAR[(v1 << 4) & 63], "==");
|
|
164
|
-
}
|
|
165
|
-
else if (remain === 2) {
|
|
166
|
-
v1 = bytes[i++];
|
|
167
|
-
v2 = bytes[i];
|
|
168
|
-
base64Str.push(BASE64_ENCODE_CHAR[v1 >>> 2], BASE64_ENCODE_CHAR[((v1 << 4) | (v2 >>> 4)) & 63], BASE64_ENCODE_CHAR[(v2 << 2) & 63], "=");
|
|
169
|
-
}
|
|
170
|
-
return base64Str.join("");
|
|
237
|
+
if (!str)
|
|
238
|
+
return "";
|
|
239
|
+
const bytes = Array.from(str).map((c) => c.charCodeAt(0));
|
|
240
|
+
return bytesToBase64Chars(bytes);
|
|
171
241
|
};
|
|
242
|
+
// 纯JS版atob
|
|
172
243
|
atob = function (base64Str) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (remain === 2) {
|
|
185
|
-
v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
|
|
186
|
-
v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
|
|
187
|
-
str.push(String.fromCharCode(((v1 << 2) | (v2 >>> 4)) & 255));
|
|
188
|
-
}
|
|
189
|
-
else if (remain === 3) {
|
|
190
|
-
v1 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
|
|
191
|
-
v2 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
|
|
192
|
-
v3 = BASE64_DECODE_CHAR[base64Str.charAt(i++)];
|
|
193
|
-
str.push(String.fromCharCode(((v1 << 2) | (v2 >>> 4)) & 255), String.fromCharCode(((v2 << 4) | (v3 >>> 2)) & 255));
|
|
194
|
-
}
|
|
195
|
-
return str.join("");
|
|
244
|
+
if (!base64Str)
|
|
245
|
+
return "";
|
|
246
|
+
const bytes = decodeAsBytes(base64Str);
|
|
247
|
+
return String.fromCharCode.apply(null, bytes);
|
|
248
|
+
};
|
|
249
|
+
// 纯JS版UTF8编码/解码
|
|
250
|
+
utf8Base64Encode = function (str) {
|
|
251
|
+
if (!str)
|
|
252
|
+
return "";
|
|
253
|
+
const bytes = utf8ToBytes(str);
|
|
254
|
+
return bytesToBase64Chars(bytes);
|
|
196
255
|
};
|
|
197
256
|
utf8Base64Decode = function (base64Str) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
257
|
+
if (!base64Str)
|
|
258
|
+
return "";
|
|
259
|
+
const bytes = decodeAsBytes(base64Str);
|
|
260
|
+
const str = [];
|
|
261
|
+
const len = bytes.length;
|
|
262
|
+
let i = 0;
|
|
263
|
+
while (i < len) {
|
|
264
|
+
const b = bytes[i++];
|
|
202
265
|
if (b <= 0x7f) {
|
|
203
266
|
str.push(String.fromCharCode(b));
|
|
204
267
|
continue;
|
|
205
268
|
}
|
|
206
|
-
|
|
269
|
+
let c, followingChars;
|
|
270
|
+
if (b > 0xbf && b <= 0xdf) {
|
|
207
271
|
c = b & 0x1f;
|
|
208
272
|
followingChars = 1;
|
|
209
273
|
}
|
|
@@ -218,20 +282,20 @@ else if (!btoa) {
|
|
|
218
282
|
else {
|
|
219
283
|
throw new Error(ENCODING_ERROR);
|
|
220
284
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
285
|
+
// 校验后续字节合法性
|
|
286
|
+
for (let j = 0; j < followingChars; ++j) {
|
|
287
|
+
const byte = bytes[i++];
|
|
288
|
+
if (i > len || byte < 0x80 || byte > 0xbf) {
|
|
224
289
|
throw new Error(ENCODING_ERROR);
|
|
225
290
|
}
|
|
226
|
-
c
|
|
227
|
-
c += b & 0x3f;
|
|
291
|
+
c = (c << 6) + (byte & 0x3f);
|
|
228
292
|
}
|
|
229
|
-
|
|
293
|
+
// 校验Unicode范围
|
|
294
|
+
if (c >= 0xd800 && c <= 0xdfff)
|
|
230
295
|
throw new Error(ENCODING_ERROR);
|
|
231
|
-
|
|
232
|
-
if (c > 0x10ffff) {
|
|
296
|
+
if (c > 0x10ffff)
|
|
233
297
|
throw new Error(ENCODING_ERROR);
|
|
234
|
-
|
|
298
|
+
// 转换为字符
|
|
235
299
|
if (c <= 0xffff) {
|
|
236
300
|
str.push(String.fromCharCode(c));
|
|
237
301
|
}
|
|
@@ -242,12 +306,16 @@ else if (!btoa) {
|
|
|
242
306
|
}
|
|
243
307
|
return str.join("");
|
|
244
308
|
};
|
|
309
|
+
// 3. 浏览器原生支持btoa/atob
|
|
245
310
|
}
|
|
246
311
|
else {
|
|
247
312
|
utf8Base64Encode = function (str) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
313
|
+
if (!str)
|
|
314
|
+
return "";
|
|
315
|
+
const result = [];
|
|
316
|
+
const len = str.length;
|
|
317
|
+
for (let i = 0; i < len; i++) {
|
|
318
|
+
const charcode = str.charCodeAt(i);
|
|
251
319
|
if (charcode < 0x80) {
|
|
252
320
|
result.push(String.fromCharCode(charcode));
|
|
253
321
|
}
|
|
@@ -258,25 +326,32 @@ else {
|
|
|
258
326
|
result.push(String.fromCharCode(0xe0 | (charcode >> 12)), String.fromCharCode(0x80 | ((charcode >> 6) & 0x3f)), String.fromCharCode(0x80 | (charcode & 0x3f)));
|
|
259
327
|
}
|
|
260
328
|
else {
|
|
261
|
-
|
|
262
|
-
result.push(String.fromCharCode(0xf0 | (
|
|
329
|
+
const code = 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(++i) & 0x3ff));
|
|
330
|
+
result.push(String.fromCharCode(0xf0 | (code >> 18)), String.fromCharCode(0x80 | ((code >> 12) & 0x3f)), String.fromCharCode(0x80 | ((code >> 6) & 0x3f)), String.fromCharCode(0x80 | (code & 0x3f)));
|
|
263
331
|
}
|
|
264
332
|
}
|
|
265
333
|
return btoa(result.join(""));
|
|
266
334
|
};
|
|
267
335
|
utf8Base64Decode = function (base64Str) {
|
|
268
|
-
|
|
269
|
-
|
|
336
|
+
if (!base64Str)
|
|
337
|
+
return "";
|
|
338
|
+
const tmpStr = atob(base64Str.replace(/-/g, "+").replace(/_/g, "/"));
|
|
339
|
+
// 替换Unicode转义,避免ESLint控制字符警告
|
|
340
|
+
// eslint-disable-next-line no-control-regex
|
|
341
|
+
if (!/[^\u0000-\u007F]/.test(tmpStr)) {
|
|
270
342
|
return tmpStr;
|
|
271
343
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
344
|
+
const str = [];
|
|
345
|
+
const len = tmpStr.length;
|
|
346
|
+
let i = 0;
|
|
347
|
+
while (i < len) {
|
|
348
|
+
const b = tmpStr.charCodeAt(i++);
|
|
275
349
|
if (b <= 0x7f) {
|
|
276
350
|
str.push(String.fromCharCode(b));
|
|
277
351
|
continue;
|
|
278
352
|
}
|
|
279
|
-
|
|
353
|
+
let c, followingChars;
|
|
354
|
+
if (b > 0xbf && b <= 0xdf) {
|
|
280
355
|
c = b & 0x1f;
|
|
281
356
|
followingChars = 1;
|
|
282
357
|
}
|
|
@@ -291,20 +366,16 @@ else {
|
|
|
291
366
|
else {
|
|
292
367
|
throw new Error(ENCODING_ERROR);
|
|
293
368
|
}
|
|
294
|
-
for (
|
|
295
|
-
|
|
296
|
-
if (
|
|
369
|
+
for (let j = 0; j < followingChars; ++j) {
|
|
370
|
+
const byte = tmpStr.charCodeAt(i++);
|
|
371
|
+
if (i > len || byte < 0x80 || byte > 0xbf)
|
|
297
372
|
throw new Error(ENCODING_ERROR);
|
|
298
|
-
|
|
299
|
-
c <<= 6;
|
|
300
|
-
c += b & 0x3f;
|
|
373
|
+
c = (c << 6) + (byte & 0x3f);
|
|
301
374
|
}
|
|
302
|
-
if (c >= 0xd800 && c <= 0xdfff)
|
|
375
|
+
if (c >= 0xd800 && c <= 0xdfff)
|
|
303
376
|
throw new Error(ENCODING_ERROR);
|
|
304
|
-
|
|
305
|
-
if (c > 0x10ffff) {
|
|
377
|
+
if (c > 0x10ffff)
|
|
306
378
|
throw new Error(ENCODING_ERROR);
|
|
307
|
-
}
|
|
308
379
|
if (c <= 0xffff) {
|
|
309
380
|
str.push(String.fromCharCode(c));
|
|
310
381
|
}
|
|
@@ -316,33 +387,154 @@ else {
|
|
|
316
387
|
return str.join("");
|
|
317
388
|
};
|
|
318
389
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
390
|
+
// ======================== 类型转换工具函数(全部保留)========================
|
|
391
|
+
/**
|
|
392
|
+
* Uint8Array转Base64字符串
|
|
393
|
+
* @param {Uint8Array} uint8Array 字节数组
|
|
394
|
+
* @param {boolean} [urlSafe=false] 是否URL安全
|
|
395
|
+
* @returns {string} Base64字符串
|
|
396
|
+
*/
|
|
397
|
+
const fromUint8Array = function (uint8Array, urlSafe = false) {
|
|
398
|
+
if (!(uint8Array instanceof Uint8Array)) {
|
|
399
|
+
throw new TypeError("fromUint8Array方法仅支持Uint8Array输入");
|
|
400
|
+
}
|
|
401
|
+
const bytes = Array.from(uint8Array);
|
|
402
|
+
let result = bytesToBase64Chars(bytes);
|
|
403
|
+
if (urlSafe) {
|
|
404
|
+
result = result.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
405
|
+
}
|
|
406
|
+
return result;
|
|
407
|
+
};
|
|
408
|
+
/**
|
|
409
|
+
* Base64字符串转Uint8Array
|
|
410
|
+
* @param {string} base64Str Base64字符串
|
|
411
|
+
* @param {boolean} [urlSafe=false] 是否URL安全
|
|
412
|
+
* @returns {Uint8Array} 字节数组
|
|
413
|
+
*/
|
|
414
|
+
const toUint8Array = function (base64Str, urlSafe = false) {
|
|
415
|
+
if (typeof base64Str !== "string") {
|
|
416
|
+
throw new TypeError("toUint8Array方法仅支持字符串输入");
|
|
323
417
|
}
|
|
418
|
+
// 处理URL安全字符
|
|
419
|
+
if (urlSafe) {
|
|
420
|
+
base64Str = base64Str.replace(/-/g, "+").replace(/_/g, "/");
|
|
421
|
+
}
|
|
422
|
+
const bytes = decodeAsBytes(base64Str);
|
|
423
|
+
return new Uint8Array(bytes);
|
|
424
|
+
};
|
|
425
|
+
/**
|
|
426
|
+
* 十六进制字符串转Base64字符串
|
|
427
|
+
* @param {string} hexStr 十六进制字符串
|
|
428
|
+
* @param {boolean} [urlSafe=false] 是否URL安全
|
|
429
|
+
* @returns {string} Base64字符串
|
|
430
|
+
*/
|
|
431
|
+
const fromHex = function (hexStr, urlSafe = false) {
|
|
432
|
+
if (typeof hexStr !== "string" || !/^[0-9a-fA-F]+$/.test(hexStr)) {
|
|
433
|
+
throw new TypeError("fromHex方法仅支持十六进制字符串输入");
|
|
434
|
+
}
|
|
435
|
+
// 补全偶数长度
|
|
436
|
+
const str = hexStr.length % 2 ? `0${hexStr}` : hexStr;
|
|
437
|
+
const bytes = new Array(str.length / 2);
|
|
438
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
439
|
+
bytes[i] = parseInt(str.substr(i * 2, 2), 16);
|
|
440
|
+
}
|
|
441
|
+
let result = bytesToBase64Chars(bytes);
|
|
442
|
+
if (urlSafe) {
|
|
443
|
+
result = result.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
444
|
+
}
|
|
445
|
+
return result;
|
|
446
|
+
};
|
|
447
|
+
/**
|
|
448
|
+
* Base64字符串转十六进制字符串
|
|
449
|
+
* @param {string} base64Str Base64字符串
|
|
450
|
+
* @param {boolean} [urlSafe=false] 是否URL安全
|
|
451
|
+
* @returns {string} 十六进制字符串
|
|
452
|
+
*/
|
|
453
|
+
const toHex = function (base64Str, urlSafe = false) {
|
|
454
|
+
if (typeof base64Str !== "string") {
|
|
455
|
+
throw new TypeError("toHex方法仅支持字符串输入");
|
|
456
|
+
}
|
|
457
|
+
// 处理URL安全字符
|
|
458
|
+
if (urlSafe) {
|
|
459
|
+
base64Str = base64Str.replace(/-/g, "+").replace(/_/g, "/");
|
|
460
|
+
}
|
|
461
|
+
const bytes = decodeAsBytes(base64Str);
|
|
462
|
+
return Array.from(bytes)
|
|
463
|
+
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
464
|
+
.join("");
|
|
465
|
+
};
|
|
466
|
+
// ======================== 核心方法(仅删除asciiOnly开关,默认UTF8)========================
|
|
467
|
+
/**
|
|
468
|
+
* Base64编码(高性能、高健壮性版,默认UTF8)
|
|
469
|
+
* @param {string | number[] | Uint8Array | ArrayBuffer} data 待编码数据
|
|
470
|
+
* @param {boolean} [urlSafe=false] 是否生成URL安全的Base64
|
|
471
|
+
* @returns {string} Base64字符串
|
|
472
|
+
*/
|
|
473
|
+
const encode = function (data, urlSafe = false) {
|
|
474
|
+
// 空值快速返回
|
|
475
|
+
if (data == null)
|
|
476
|
+
return "";
|
|
477
|
+
const notString = typeof data !== "string";
|
|
478
|
+
let result = "";
|
|
324
479
|
if (notString) {
|
|
325
|
-
|
|
480
|
+
// 处理ArrayBuffer
|
|
481
|
+
if (data.constructor === root.ArrayBuffer) {
|
|
482
|
+
data = new Uint8Array(data);
|
|
483
|
+
}
|
|
484
|
+
// 处理字节数组/Uint8Array
|
|
485
|
+
result = encodeFromBytes(data);
|
|
326
486
|
}
|
|
327
487
|
else {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
488
|
+
// 空字符串快速返回
|
|
489
|
+
if (data === "")
|
|
490
|
+
return "";
|
|
491
|
+
// 强制走UTF8编码(删掉asciiOnly判断,直接用utf8Base64Encode)
|
|
492
|
+
result = utf8Base64Encode(data);
|
|
493
|
+
}
|
|
494
|
+
// URL安全处理:替换+->-,/->_,去掉=
|
|
495
|
+
if (urlSafe) {
|
|
496
|
+
result = result.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
334
497
|
}
|
|
498
|
+
return result;
|
|
335
499
|
};
|
|
336
|
-
|
|
500
|
+
/**
|
|
501
|
+
* Base64解码(高性能、高健壮性版,默认UTF8)
|
|
502
|
+
* @param {string} base64Str 待解码的Base64字符串
|
|
503
|
+
* @returns {string} 解码后的UTF8字符串
|
|
504
|
+
*/
|
|
505
|
+
const decode = function (base64Str) {
|
|
506
|
+
// 空值快速返回
|
|
507
|
+
if (base64Str == null || base64Str === "")
|
|
508
|
+
return "";
|
|
509
|
+
// 处理URL安全的Base64
|
|
510
|
+
base64Str = base64Str.replace(/-/g, "+").replace(/_/g, "/");
|
|
337
511
|
base64Str = cleanBase64Str(base64Str);
|
|
338
|
-
|
|
512
|
+
// 强制走UTF8解码(删掉asciiOnly判断,直接用utf8Base64Decode)
|
|
513
|
+
return utf8Base64Decode(base64Str);
|
|
514
|
+
};
|
|
515
|
+
// ======================== URL安全专用方法(同步删除asciiOnly开关)========================
|
|
516
|
+
/**
|
|
517
|
+
* URL安全Base64编码(专用方法,等价于encode(data, true))
|
|
518
|
+
* @param {string | number[] | Uint8Array | ArrayBuffer} data 待编码数据
|
|
519
|
+
* @returns {string} URL安全的Base64字符串
|
|
520
|
+
*/
|
|
521
|
+
const encodeURI = function (data) {
|
|
522
|
+
return encode(data, true);
|
|
523
|
+
};
|
|
524
|
+
/**
|
|
525
|
+
* URL安全Base64解码(专用方法,兼容URL安全字符)
|
|
526
|
+
* @param {string} base64Str URL安全的Base64字符串
|
|
527
|
+
* @returns {string} 解码后的UTF8字符串
|
|
528
|
+
*/
|
|
529
|
+
const decodeURI = function (base64Str) {
|
|
530
|
+
return decode(base64Str);
|
|
339
531
|
};
|
|
340
|
-
/* 以下是内部实现需要的es模块化导出方法 */
|
|
341
|
-
const utf8Encode = utf8Base64Encode;
|
|
342
|
-
const utf8Decode = utf8Base64Decode;
|
|
343
532
|
|
|
344
533
|
exports.decode = decode;
|
|
345
|
-
exports.
|
|
534
|
+
exports.decodeURI = decodeURI;
|
|
346
535
|
exports.encode = encode;
|
|
347
|
-
exports.
|
|
348
|
-
exports.
|
|
536
|
+
exports.encodeURI = encodeURI;
|
|
537
|
+
exports.fromHex = fromHex;
|
|
538
|
+
exports.fromUint8Array = fromUint8Array;
|
|
539
|
+
exports.toHex = toHex;
|
|
540
|
+
exports.toUint8Array = toUint8Array;
|