base64.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2018
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. // derived from the work of Jameson Little - https://github.com/beatgammit/base64-js
  25. this.base64 = this.base64 || (() => {
  26. const lookup = [];
  27. const revLookup = [];
  28. const Arr = typeof Uint8Array !== "undefined" ? Uint8Array : Array;
  29. const code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  30. for (let i = 0, len = code.length; i < len; ++i) {
  31. lookup[i] = code[i];
  32. revLookup[code.charCodeAt(i)] = i;
  33. }
  34. // Support decoding URL-safe base64 strings, as Node.js does.
  35. // See: https://en.wikipedia.org/wiki/Base64#URL_applications
  36. revLookup["-".charCodeAt(0)] = 62;
  37. revLookup["_".charCodeAt(0)] = 63;
  38. function getLens(b64) {
  39. const len = b64.length;
  40. if (len % 4 > 0) {
  41. throw new Error("Invalid string. Length must be a multiple of 4");
  42. }
  43. // Trim off extra bytes after placeholder bytes are found
  44. // See: https://github.com/beatgammit/base64-js/issues/42
  45. let validLen = b64.indexOf("=");
  46. if (validLen === -1) validLen = len;
  47. const placeHoldersLen = validLen === len
  48. ? 0
  49. : 4 - (validLen % 4);
  50. return [validLen, placeHoldersLen];
  51. }
  52. // base64 is 4/3 + up to two characters of the original data
  53. function byteLength(b64) {
  54. const lens = getLens(b64);
  55. const validLen = lens[0];
  56. const placeHoldersLen = lens[1];
  57. return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen;
  58. }
  59. function _byteLength(b64, validLen, placeHoldersLen) {
  60. return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen;
  61. }
  62. function toByteArray(b64) {
  63. let tmp;
  64. const lens = getLens(b64);
  65. const validLen = lens[0];
  66. const placeHoldersLen = lens[1];
  67. const arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));
  68. let curByte = 0;
  69. // if there are placeholders, only get up to the last complete 4 chars
  70. const len = placeHoldersLen > 0
  71. ? validLen - 4
  72. : validLen;
  73. let i;
  74. for (i = 0; i < len; i += 4) {
  75. tmp =
  76. (revLookup[b64.charCodeAt(i)] << 18) |
  77. (revLookup[b64.charCodeAt(i + 1)] << 12) |
  78. (revLookup[b64.charCodeAt(i + 2)] << 6) |
  79. revLookup[b64.charCodeAt(i + 3)];
  80. arr[curByte++] = (tmp >> 16) & 0xFF;
  81. arr[curByte++] = (tmp >> 8) & 0xFF;
  82. arr[curByte++] = tmp & 0xFF;
  83. }
  84. if (placeHoldersLen === 2) {
  85. tmp =
  86. (revLookup[b64.charCodeAt(i)] << 2) |
  87. (revLookup[b64.charCodeAt(i + 1)] >> 4);
  88. arr[curByte++] = tmp & 0xFF;
  89. }
  90. if (placeHoldersLen === 1) {
  91. tmp =
  92. (revLookup[b64.charCodeAt(i)] << 10) |
  93. (revLookup[b64.charCodeAt(i + 1)] << 4) |
  94. (revLookup[b64.charCodeAt(i + 2)] >> 2);
  95. arr[curByte++] = (tmp >> 8) & 0xFF;
  96. arr[curByte++] = tmp & 0xFF;
  97. }
  98. return arr;
  99. }
  100. function tripletToBase64(num) {
  101. return lookup[num >> 18 & 0x3F] +
  102. lookup[num >> 12 & 0x3F] +
  103. lookup[num >> 6 & 0x3F] +
  104. lookup[num & 0x3F];
  105. }
  106. function encodeChunk(uint8, start, end) {
  107. let tmp;
  108. let output = "";
  109. for (let i = start; i < end; i += 3) {
  110. tmp =
  111. ((uint8[i] << 16) & 0xFF0000) +
  112. ((uint8[i + 1] << 8) & 0xFF00) +
  113. (uint8[i + 2] & 0xFF);
  114. output += tripletToBase64(tmp);
  115. }
  116. return output;
  117. }
  118. function fromByteArray(uint8) {
  119. let tmp;
  120. const len = uint8.length;
  121. const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
  122. const parts = [];
  123. const maxChunkLength = 1572864; // must be multiple of 3
  124. // go through the array every three bytes, we"ll deal with trailing stuff later
  125. for (let i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
  126. parts.push(encodeChunk(
  127. uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)
  128. ));
  129. }
  130. // pad the end with zeros, but make sure to not forget the extra bytes
  131. if (extraBytes === 1) {
  132. tmp = uint8[len - 1];
  133. parts.push(
  134. lookup[tmp >> 2] +
  135. lookup[(tmp << 4) & 0x3F] +
  136. "=="
  137. );
  138. } else if (extraBytes === 2) {
  139. tmp = (uint8[len - 2] << 8) + uint8[len - 1];
  140. parts.push(
  141. lookup[tmp >> 10] +
  142. lookup[(tmp >> 4) & 0x3F] +
  143. lookup[(tmp << 2) & 0x3F] +
  144. "="
  145. );
  146. }
  147. return parts.join("");
  148. }
  149. return {
  150. byteLength,
  151. toByteArray,
  152. fromByteArray
  153. };
  154. })();