1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | const b64lookup = [];
|
12 | const urlLookup = [];
|
13 | const revLookup = [];
|
14 | const CODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
15 | const CODE_B64 = CODE + '+/';
|
16 | const CODE_URL = CODE + '-_';
|
17 | const PAD = '=';
|
18 | const MAX_CHUNK_LENGTH = 16383;
|
19 | for (let i = 0, len = CODE_B64.length; i < len; ++i) {
|
20 | b64lookup[i] = CODE_B64[i];
|
21 | urlLookup[i] = CODE_URL[i];
|
22 | revLookup[CODE_B64.charCodeAt(i)] = i;
|
23 | }
|
24 |
|
25 |
|
26 | revLookup['-'.charCodeAt(0)] = 62;
|
27 | revLookup['_'.charCodeAt(0)] = 63;
|
28 | function getLens(b64) {
|
29 | const len = b64.length;
|
30 |
|
31 |
|
32 | let validLen = b64.indexOf(PAD);
|
33 | if (validLen === -1)
|
34 | validLen = len;
|
35 | const placeHoldersLen = validLen === len
|
36 | ? 0
|
37 | : 4 - (validLen % 4);
|
38 | return [validLen, placeHoldersLen];
|
39 | }
|
40 | function _byteLength(validLen, placeHoldersLen) {
|
41 | return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen;
|
42 | }
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 | export function toByteArray(str) {
|
52 | let tmp;
|
53 | switch (str.length % 4) {
|
54 | case 2:
|
55 | str += "==";
|
56 | break;
|
57 | case 3:
|
58 | str += "=";
|
59 | break;
|
60 | }
|
61 | const [validLen, placeHoldersLen] = getLens(str);
|
62 | const arr = new Uint8Array(_byteLength(validLen, placeHoldersLen));
|
63 | let curByte = 0;
|
64 |
|
65 | const len = placeHoldersLen > 0
|
66 | ? validLen - 4
|
67 | : validLen;
|
68 | let i;
|
69 | for (i = 0; i < len; i += 4) {
|
70 | tmp =
|
71 | (revLookup[str.charCodeAt(i)] << 18) |
|
72 | (revLookup[str.charCodeAt(i + 1)] << 12) |
|
73 | (revLookup[str.charCodeAt(i + 2)] << 6) |
|
74 | (revLookup[str.charCodeAt(i + 3)]);
|
75 | arr[curByte++] = (tmp >> 16) & 0xff;
|
76 | arr[curByte++] = (tmp >> 8) & 0xff;
|
77 | arr[curByte++] = (tmp) & 0xff;
|
78 | }
|
79 | if (placeHoldersLen === 2) {
|
80 | tmp =
|
81 | (revLookup[str.charCodeAt(i)] << 2) |
|
82 | (revLookup[str.charCodeAt(i + 1)] >> 4);
|
83 | arr[curByte++] = tmp & 0xff;
|
84 | }
|
85 | if (placeHoldersLen === 1) {
|
86 | tmp =
|
87 | (revLookup[str.charCodeAt(i)] << 10) |
|
88 | (revLookup[str.charCodeAt(i + 1)] << 4) |
|
89 | (revLookup[str.charCodeAt(i + 2)] >> 2);
|
90 | arr[curByte++] = (tmp >> 8) & 0xff;
|
91 | arr[curByte++] = tmp & 0xff;
|
92 | }
|
93 | return arr;
|
94 | }
|
95 | function tripletToBase64(lookup, num) {
|
96 | return (lookup[num >> 18 & 0x3f] +
|
97 | lookup[num >> 12 & 0x3f] +
|
98 | lookup[num >> 6 & 0x3f] +
|
99 | lookup[num & 0x3f]);
|
100 | }
|
101 | function encodeChunk(lookup, view, start, end) {
|
102 | let tmp;
|
103 | const output = new Array((end - start) / 3);
|
104 | for (let i = start, j = 0; i < end; i += 3, j++) {
|
105 | tmp =
|
106 | ((view.getUint8(i) << 16) & 0xff0000) +
|
107 | ((view.getUint8(i + 1) << 8) & 0x00ff00) +
|
108 | (view.getUint8(i + 2) & 0x0000ff);
|
109 | output[j] = tripletToBase64(lookup, tmp);
|
110 | }
|
111 | return output.join('');
|
112 | }
|
113 | const bs2dv = (bs) => bs instanceof ArrayBuffer
|
114 | ? new DataView(bs)
|
115 | : new DataView(bs.buffer, bs.byteOffset, bs.byteLength);
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 | export function fromByteArray(bufferSource, urlFriendly = false) {
|
123 | const view = bs2dv(bufferSource);
|
124 | const len = view.byteLength;
|
125 | const extraBytes = len % 3;
|
126 | const len2 = len - extraBytes;
|
127 | const parts = new Array(Math.floor(len2 / MAX_CHUNK_LENGTH) + Math.sign(extraBytes));
|
128 | const lookup = urlFriendly ? urlLookup : b64lookup;
|
129 | const pad = urlFriendly ? '' : PAD;
|
130 |
|
131 |
|
132 | let j = 0;
|
133 | for (let i = 0; i < len2; i += MAX_CHUNK_LENGTH) {
|
134 | parts[j++] = encodeChunk(lookup, view, i, (i + MAX_CHUNK_LENGTH) > len2 ? len2 : (i + MAX_CHUNK_LENGTH));
|
135 | }
|
136 |
|
137 | if (extraBytes === 1) {
|
138 | const tmp = view.getUint8(len - 1);
|
139 | parts[j] = (lookup[tmp >> 2] +
|
140 | lookup[(tmp << 4) & 0x3f] +
|
141 | pad + pad);
|
142 | }
|
143 | else if (extraBytes === 2) {
|
144 | const tmp = (view.getUint8(len - 2) << 8) + view.getUint8(len - 1);
|
145 | parts[j] = (lookup[tmp >> 10] +
|
146 | lookup[(tmp >> 4) & 0x3f] +
|
147 | lookup[(tmp << 2) & 0x3f] +
|
148 | pad);
|
149 | }
|
150 | return parts.join('');
|
151 | }
|
152 | export { fromByteArray as encode, toByteArray as decode, };
|
153 |
|
\ | No newline at end of file |