base64.js 11 KB

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