UNPKG

5.6 kBJavaScriptView Raw
1/**
2 * Slightly modernized version of [`base64-js`][1].
3 * Performance is slightly improved due to pre-allocating arrays.
4 *
5 * This version drops support for platforms that don't provide
6 * `Uint8Array` and `DataView`. Use the original in those cases.
7 *
8 * [1]: https://github.com/beatgammit/base64-js
9 * [2]: https://tools.ietf.org/html/rfc3986#section-2.3
10 */
11const b64lookup = [];
12const urlLookup = [];
13const revLookup = [];
14const CODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
15const CODE_B64 = CODE + '+/';
16const CODE_URL = CODE + '-_';
17const PAD = '=';
18const MAX_CHUNK_LENGTH = 16383; // must be multiple of 3
19for (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// Support decoding URL-safe base64 strings, as Node.js does.
25// See: https://en.wikipedia.org/wiki/Base64#URL_applications
26revLookup['-'.charCodeAt(0)] = 62;
27revLookup['_'.charCodeAt(0)] = 63;
28function getLens(b64) {
29 const len = b64.length;
30 // Trim off extra bytes after placeholder bytes are found
31 // See: https://github.com/beatgammit/base64-js/issues/42
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}
40function _byteLength(validLen, placeHoldersLen) {
41 return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen;
42}
43/**
44 * Takes a base 64 string and converts it to an array buffer.
45 * Accepts both regular Base64 and the URL-friendly variant,
46 * where `+` => `-`, `/` => `_`, and the padding character is omitted.
47 *
48 * @param str A Base64 string in either regular or URL-friendly representation.
49 * @returns The binary data as `Uint8Array`.
50 */
51export 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 // if there are placeholders, only get up to the last complete 4 chars
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}
95function tripletToBase64(lookup, num) {
96 return (lookup[num >> 18 & 0x3f] +
97 lookup[num >> 12 & 0x3f] +
98 lookup[num >> 6 & 0x3f] +
99 lookup[num & 0x3f]);
100}
101function 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}
113const bs2dv = (bs) => bs instanceof ArrayBuffer
114 ? new DataView(bs)
115 : new DataView(bs.buffer, bs.byteOffset, bs.byteLength);
116/**
117 * Encodes binary data provided in an array buffer as a Base64 string.
118 * @param bufferSource The raw data to encode.
119 * @param urlFriendly Set to true to encode in a URL-friendly way.
120 * @returns The contents a Base64 string.
121 */
122export function fromByteArray(bufferSource, urlFriendly = false) {
123 const view = bs2dv(bufferSource);
124 const len = view.byteLength;
125 const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
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 // Go through the array every three bytes, we'll deal with trailing stuff
131 // later
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 // pad the end with zeros, but make sure to not forget the extra bytes
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}
152export { fromByteArray as encode, toByteArray as decode, };
153//# sourceMappingURL=base64-js.js.map
\No newline at end of file