Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/crypt/base64.js
2868 views
1
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Base64 en/decoding. Not much to say here except that we
17
* work with decoded values in arrays of bytes. By "byte" I mean a number
18
* in [0, 255].
19
*
20
* @author [email protected] (Gavin Doughtie)
21
*/
22
23
goog.provide('goog.crypt.base64');
24
25
goog.require('goog.asserts');
26
goog.require('goog.crypt');
27
goog.require('goog.string');
28
goog.require('goog.userAgent');
29
goog.require('goog.userAgent.product');
30
31
// Static lookup maps, lazily populated by init_()
32
33
34
/**
35
* Maps bytes to characters.
36
* @type {Object}
37
* @private
38
*/
39
goog.crypt.base64.byteToCharMap_ = null;
40
41
42
/**
43
* Maps characters to bytes. Used for normal and websafe characters.
44
* @type {Object}
45
* @private
46
*/
47
goog.crypt.base64.charToByteMap_ = null;
48
49
50
/**
51
* Maps bytes to websafe characters.
52
* @type {Object}
53
* @private
54
*/
55
goog.crypt.base64.byteToCharMapWebSafe_ = null;
56
57
58
/**
59
* Our default alphabet, shared between
60
* ENCODED_VALS and ENCODED_VALS_WEBSAFE
61
* @type {string}
62
*/
63
goog.crypt.base64.ENCODED_VALS_BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
64
'abcdefghijklmnopqrstuvwxyz' +
65
'0123456789';
66
67
68
/**
69
* Our default alphabet. Value 64 (=) is special; it means "nothing."
70
* @type {string}
71
*/
72
goog.crypt.base64.ENCODED_VALS = goog.crypt.base64.ENCODED_VALS_BASE + '+/=';
73
74
75
/**
76
* Our websafe alphabet.
77
* @type {string}
78
*/
79
goog.crypt.base64.ENCODED_VALS_WEBSAFE =
80
goog.crypt.base64.ENCODED_VALS_BASE + '-_.';
81
82
83
/**
84
* White list of implementations with known-good native atob and btoa functions.
85
* Listing these explicitly (via the ASSUME_* wrappers) benefits dead-code
86
* removal in per-browser compilations.
87
* @private {boolean}
88
*/
89
goog.crypt.base64.ASSUME_NATIVE_SUPPORT_ = goog.userAgent.GECKO ||
90
(goog.userAgent.WEBKIT && !goog.userAgent.product.SAFARI) ||
91
goog.userAgent.OPERA;
92
93
94
/**
95
* Does this browser have a working btoa function?
96
* @private {boolean}
97
*/
98
goog.crypt.base64.HAS_NATIVE_ENCODE_ =
99
goog.crypt.base64.ASSUME_NATIVE_SUPPORT_ ||
100
typeof(goog.global.btoa) == 'function';
101
102
103
/**
104
* Does this browser have a working atob function?
105
* We blacklist known-bad implementations:
106
* - IE (10+) added atob() but it does not tolerate whitespace on the input.
107
* @private {boolean}
108
*/
109
goog.crypt.base64.HAS_NATIVE_DECODE_ =
110
goog.crypt.base64.ASSUME_NATIVE_SUPPORT_ ||
111
(!goog.userAgent.product.SAFARI && !goog.userAgent.IE &&
112
typeof(goog.global.atob) == 'function');
113
114
115
/**
116
* Base64-encode an array of bytes.
117
*
118
* @param {Array<number>|Uint8Array} input An array of bytes (numbers with
119
* value in [0, 255]) to encode.
120
* @param {boolean=} opt_webSafe True indicates we should use the alternative
121
* alphabet, which does not require escaping for use in URLs.
122
* @return {string} The base64 encoded string.
123
*/
124
goog.crypt.base64.encodeByteArray = function(input, opt_webSafe) {
125
// Assert avoids runtime dependency on goog.isArrayLike, which helps reduce
126
// size of jscompiler output, and which yields slight performance increase.
127
goog.asserts.assert(
128
goog.isArrayLike(input), 'encodeByteArray takes an array as a parameter');
129
130
goog.crypt.base64.init_();
131
132
var byteToCharMap = opt_webSafe ? goog.crypt.base64.byteToCharMapWebSafe_ :
133
goog.crypt.base64.byteToCharMap_;
134
135
var output = [];
136
137
for (var i = 0; i < input.length; i += 3) {
138
var byte1 = input[i];
139
var haveByte2 = i + 1 < input.length;
140
var byte2 = haveByte2 ? input[i + 1] : 0;
141
var haveByte3 = i + 2 < input.length;
142
var byte3 = haveByte3 ? input[i + 2] : 0;
143
144
var outByte1 = byte1 >> 2;
145
var outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4);
146
var outByte3 = ((byte2 & 0x0F) << 2) | (byte3 >> 6);
147
var outByte4 = byte3 & 0x3F;
148
149
if (!haveByte3) {
150
outByte4 = 64;
151
152
if (!haveByte2) {
153
outByte3 = 64;
154
}
155
}
156
157
output.push(
158
byteToCharMap[outByte1], byteToCharMap[outByte2],
159
byteToCharMap[outByte3], byteToCharMap[outByte4]);
160
}
161
162
return output.join('');
163
};
164
165
166
/**
167
* Base64-encode a string.
168
*
169
* @param {string} input A string to encode.
170
* @param {boolean=} opt_webSafe True indicates we should use the alternative
171
* alphabet, which does not require escaping for use in URLs.
172
* @return {string} The base64 encoded string.
173
*/
174
goog.crypt.base64.encodeString = function(input, opt_webSafe) {
175
// Shortcut for browsers that implement
176
// a native base64 encoder in the form of "btoa/atob"
177
if (goog.crypt.base64.HAS_NATIVE_ENCODE_ && !opt_webSafe) {
178
return goog.global.btoa(input);
179
}
180
return goog.crypt.base64.encodeByteArray(
181
goog.crypt.stringToByteArray(input), opt_webSafe);
182
};
183
184
185
/**
186
* Base64-decode a string.
187
*
188
* @param {string} input Input to decode. Any whitespace is ignored, and the
189
* input maybe encoded with either supported alphabet (or a mix thereof).
190
* @param {boolean=} opt_webSafe True indicates we should use the alternative
191
* alphabet, which does not require escaping for use in URLs. Note that
192
* passing false may also still allow webSafe input decoding, when the
193
* fallback decoder is used on browsers without native support.
194
* @return {string} string representing the decoded value.
195
*/
196
goog.crypt.base64.decodeString = function(input, opt_webSafe) {
197
// Shortcut for browsers that implement
198
// a native base64 encoder in the form of "btoa/atob"
199
if (goog.crypt.base64.HAS_NATIVE_DECODE_ && !opt_webSafe) {
200
return goog.global.atob(input);
201
}
202
var output = '';
203
function pushByte(b) { output += String.fromCharCode(b); }
204
205
goog.crypt.base64.decodeStringInternal_(input, pushByte);
206
207
return output;
208
};
209
210
211
/**
212
* Base64-decode a string to an Array of numbers.
213
*
214
* In base-64 decoding, groups of four characters are converted into three
215
* bytes. If the encoder did not apply padding, the input length may not
216
* be a multiple of 4.
217
*
218
* In this case, the last group will have fewer than 4 characters, and
219
* padding will be inferred. If the group has one or two characters, it decodes
220
* to one byte. If the group has three characters, it decodes to two bytes.
221
*
222
* @param {string} input Input to decode. Any whitespace is ignored, and the
223
* input maybe encoded with either supported alphabet (or a mix thereof).
224
* @param {boolean=} opt_ignored Unused parameter, retained for compatibility.
225
* @return {!Array<number>} bytes representing the decoded value.
226
*/
227
goog.crypt.base64.decodeStringToByteArray = function(input, opt_ignored) {
228
var output = [];
229
function pushByte(b) { output.push(b); }
230
231
goog.crypt.base64.decodeStringInternal_(input, pushByte);
232
233
return output;
234
};
235
236
237
/**
238
* Base64-decode a string to a Uint8Array.
239
*
240
* Note that Uint8Array is not supported on older browsers, e.g. IE < 10.
241
* @see http://caniuse.com/uint8array
242
*
243
* In base-64 decoding, groups of four characters are converted into three
244
* bytes. If the encoder did not apply padding, the input length may not
245
* be a multiple of 4.
246
*
247
* In this case, the last group will have fewer than 4 characters, and
248
* padding will be inferred. If the group has one or two characters, it decodes
249
* to one byte. If the group has three characters, it decodes to two bytes.
250
*
251
* @param {string} input Input to decode. Any whitespace is ignored, and the
252
* input maybe encoded with either supported alphabet (or a mix thereof).
253
* @return {!Uint8Array} bytes representing the decoded value.
254
*/
255
goog.crypt.base64.decodeStringToUint8Array = function(input) {
256
goog.asserts.assert(
257
!goog.userAgent.IE || goog.userAgent.isVersionOrHigher('10'),
258
'Browser does not support typed arrays');
259
var output = new Uint8Array(Math.ceil(input.length * 3 / 4));
260
var outLen = 0;
261
function pushByte(b) { output[outLen++] = b; }
262
263
goog.crypt.base64.decodeStringInternal_(input, pushByte);
264
265
return output.subarray(0, outLen);
266
};
267
268
269
/**
270
* @param {string} input Input to decode.
271
* @param {function(number):void} pushByte result accumulator.
272
* @private
273
*/
274
goog.crypt.base64.decodeStringInternal_ = function(input, pushByte) {
275
goog.crypt.base64.init_();
276
277
var nextCharIndex = 0;
278
/**
279
* @param {number} default_val Used for end-of-input.
280
* @return {number} The next 6-bit value, or the default for end-of-input.
281
*/
282
function getByte(default_val) {
283
while (nextCharIndex < input.length) {
284
var ch = input.charAt(nextCharIndex++);
285
var b = goog.crypt.base64.charToByteMap_[ch];
286
if (b != null) {
287
return b; // Common case: decoded the char.
288
}
289
if (!goog.string.isEmptyOrWhitespace(ch)) {
290
throw Error('Unknown base64 encoding at char: ' + ch);
291
}
292
// We encountered whitespace: loop around to the next input char.
293
}
294
return default_val; // No more input remaining.
295
}
296
297
while (true) {
298
var byte1 = getByte(-1);
299
var byte2 = getByte(0);
300
var byte3 = getByte(64);
301
var byte4 = getByte(64);
302
303
// The common case is that all four bytes are present, so if we have byte4
304
// we can skip over the truncated input special case handling.
305
if (byte4 === 64) {
306
if (byte1 === -1) {
307
return; // Terminal case: no input left to decode.
308
}
309
// Here we know an intermediate number of bytes are missing.
310
// The defaults for byte2, byte3 and byte4 apply the inferred padding
311
// rules per the public API documentation. i.e: 1 byte
312
// missing should yield 2 bytes of output, but 2 or 3 missing bytes yield
313
// a single byte of output. (Recall that 64 corresponds the padding char).
314
}
315
316
var outByte1 = (byte1 << 2) | (byte2 >> 4);
317
pushByte(outByte1);
318
319
if (byte3 != 64) {
320
var outByte2 = ((byte2 << 4) & 0xF0) | (byte3 >> 2);
321
pushByte(outByte2);
322
323
if (byte4 != 64) {
324
var outByte3 = ((byte3 << 6) & 0xC0) | byte4;
325
pushByte(outByte3);
326
}
327
}
328
}
329
};
330
331
332
/**
333
* Lazy static initialization function. Called before
334
* accessing any of the static map variables.
335
* @private
336
*/
337
goog.crypt.base64.init_ = function() {
338
if (!goog.crypt.base64.byteToCharMap_) {
339
goog.crypt.base64.byteToCharMap_ = {};
340
goog.crypt.base64.charToByteMap_ = {};
341
goog.crypt.base64.byteToCharMapWebSafe_ = {};
342
343
// We want quick mappings back and forth, so we precompute two maps.
344
for (var i = 0; i < goog.crypt.base64.ENCODED_VALS.length; i++) {
345
goog.crypt.base64.byteToCharMap_[i] =
346
goog.crypt.base64.ENCODED_VALS.charAt(i);
347
goog.crypt.base64.charToByteMap_[goog.crypt.base64.byteToCharMap_[i]] = i;
348
goog.crypt.base64.byteToCharMapWebSafe_[i] =
349
goog.crypt.base64.ENCODED_VALS_WEBSAFE.charAt(i);
350
351
// Be forgiving when decoding and correctly decode both encodings.
352
if (i >= goog.crypt.base64.ENCODED_VALS_BASE.length) {
353
goog.crypt.base64
354
.charToByteMap_[goog.crypt.base64.ENCODED_VALS_WEBSAFE.charAt(i)] =
355
i;
356
}
357
}
358
}
359
};
360
361