拓恒河湖长制全民护河平台WEB端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

297 lines
10KB

  1. /**
  2. * base64.ts
  3. *
  4. * Licensed under the BSD 3-Clause License.
  5. * http://opensource.org/licenses/BSD-3-Clause
  6. *
  7. * References:
  8. * http://en.wikipedia.org/wiki/Base64
  9. *
  10. * @author Dan Kogai (https://github.com/dankogai)
  11. */
  12. const version = '3.7.2';
  13. /**
  14. * @deprecated use lowercase `version`.
  15. */
  16. const VERSION = version;
  17. const _hasatob = typeof atob === 'function';
  18. const _hasbtoa = typeof btoa === 'function';
  19. const _hasBuffer = typeof Buffer === 'function';
  20. const _TD = typeof TextDecoder === 'function' ? new TextDecoder() : undefined;
  21. const _TE = typeof TextEncoder === 'function' ? new TextEncoder() : undefined;
  22. const b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  23. const b64chs = Array.prototype.slice.call(b64ch);
  24. const b64tab = ((a) => {
  25. let tab = {};
  26. a.forEach((c, i) => tab[c] = i);
  27. return tab;
  28. })(b64chs);
  29. const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
  30. const _fromCC = String.fromCharCode.bind(String);
  31. const _U8Afrom = typeof Uint8Array.from === 'function'
  32. ? Uint8Array.from.bind(Uint8Array)
  33. : (it, fn = (x) => x) => new Uint8Array(Array.prototype.slice.call(it, 0).map(fn));
  34. const _mkUriSafe = (src) => src
  35. .replace(/=/g, '').replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_');
  36. const _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, '');
  37. /**
  38. * polyfill version of `btoa`
  39. */
  40. const btoaPolyfill = (bin) => {
  41. // console.log('polyfilled');
  42. let u32, c0, c1, c2, asc = '';
  43. const pad = bin.length % 3;
  44. for (let i = 0; i < bin.length;) {
  45. if ((c0 = bin.charCodeAt(i++)) > 255 ||
  46. (c1 = bin.charCodeAt(i++)) > 255 ||
  47. (c2 = bin.charCodeAt(i++)) > 255)
  48. throw new TypeError('invalid character found');
  49. u32 = (c0 << 16) | (c1 << 8) | c2;
  50. asc += b64chs[u32 >> 18 & 63]
  51. + b64chs[u32 >> 12 & 63]
  52. + b64chs[u32 >> 6 & 63]
  53. + b64chs[u32 & 63];
  54. }
  55. return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc;
  56. };
  57. /**
  58. * does what `window.btoa` of web browsers do.
  59. * @param {String} bin binary string
  60. * @returns {string} Base64-encoded string
  61. */
  62. const _btoa = _hasbtoa ? (bin) => btoa(bin)
  63. : _hasBuffer ? (bin) => Buffer.from(bin, 'binary').toString('base64')
  64. : btoaPolyfill;
  65. const _fromUint8Array = _hasBuffer
  66. ? (u8a) => Buffer.from(u8a).toString('base64')
  67. : (u8a) => {
  68. // cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326
  69. const maxargs = 0x1000;
  70. let strs = [];
  71. for (let i = 0, l = u8a.length; i < l; i += maxargs) {
  72. strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs)));
  73. }
  74. return _btoa(strs.join(''));
  75. };
  76. /**
  77. * converts a Uint8Array to a Base64 string.
  78. * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5
  79. * @returns {string} Base64 string
  80. */
  81. const fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a);
  82. // This trick is found broken https://github.com/dankogai/js-base64/issues/130
  83. // const utob = (src: string) => unescape(encodeURIComponent(src));
  84. // reverting good old fationed regexp
  85. const cb_utob = (c) => {
  86. if (c.length < 2) {
  87. var cc = c.charCodeAt(0);
  88. return cc < 0x80 ? c
  89. : cc < 0x800 ? (_fromCC(0xc0 | (cc >>> 6))
  90. + _fromCC(0x80 | (cc & 0x3f)))
  91. : (_fromCC(0xe0 | ((cc >>> 12) & 0x0f))
  92. + _fromCC(0x80 | ((cc >>> 6) & 0x3f))
  93. + _fromCC(0x80 | (cc & 0x3f)));
  94. }
  95. else {
  96. var cc = 0x10000
  97. + (c.charCodeAt(0) - 0xD800) * 0x400
  98. + (c.charCodeAt(1) - 0xDC00);
  99. return (_fromCC(0xf0 | ((cc >>> 18) & 0x07))
  100. + _fromCC(0x80 | ((cc >>> 12) & 0x3f))
  101. + _fromCC(0x80 | ((cc >>> 6) & 0x3f))
  102. + _fromCC(0x80 | (cc & 0x3f)));
  103. }
  104. };
  105. const re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
  106. /**
  107. * @deprecated should have been internal use only.
  108. * @param {string} src UTF-8 string
  109. * @returns {string} UTF-16 string
  110. */
  111. const utob = (u) => u.replace(re_utob, cb_utob);
  112. //
  113. const _encode = _hasBuffer
  114. ? (s) => Buffer.from(s, 'utf8').toString('base64')
  115. : _TE
  116. ? (s) => _fromUint8Array(_TE.encode(s))
  117. : (s) => _btoa(utob(s));
  118. /**
  119. * converts a UTF-8-encoded string to a Base64 string.
  120. * @param {boolean} [urlsafe] if `true` make the result URL-safe
  121. * @returns {string} Base64 string
  122. */
  123. const encode = (src, urlsafe = false) => urlsafe
  124. ? _mkUriSafe(_encode(src))
  125. : _encode(src);
  126. /**
  127. * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5.
  128. * @returns {string} Base64 string
  129. */
  130. const encodeURI = (src) => encode(src, true);
  131. // This trick is found broken https://github.com/dankogai/js-base64/issues/130
  132. // const btou = (src: string) => decodeURIComponent(escape(src));
  133. // reverting good old fationed regexp
  134. const re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g;
  135. const cb_btou = (cccc) => {
  136. switch (cccc.length) {
  137. case 4:
  138. var cp = ((0x07 & cccc.charCodeAt(0)) << 18)
  139. | ((0x3f & cccc.charCodeAt(1)) << 12)
  140. | ((0x3f & cccc.charCodeAt(2)) << 6)
  141. | (0x3f & cccc.charCodeAt(3)), offset = cp - 0x10000;
  142. return (_fromCC((offset >>> 10) + 0xD800)
  143. + _fromCC((offset & 0x3FF) + 0xDC00));
  144. case 3:
  145. return _fromCC(((0x0f & cccc.charCodeAt(0)) << 12)
  146. | ((0x3f & cccc.charCodeAt(1)) << 6)
  147. | (0x3f & cccc.charCodeAt(2)));
  148. default:
  149. return _fromCC(((0x1f & cccc.charCodeAt(0)) << 6)
  150. | (0x3f & cccc.charCodeAt(1)));
  151. }
  152. };
  153. /**
  154. * @deprecated should have been internal use only.
  155. * @param {string} src UTF-16 string
  156. * @returns {string} UTF-8 string
  157. */
  158. const btou = (b) => b.replace(re_btou, cb_btou);
  159. /**
  160. * polyfill version of `atob`
  161. */
  162. const atobPolyfill = (asc) => {
  163. // console.log('polyfilled');
  164. asc = asc.replace(/\s+/g, '');
  165. if (!b64re.test(asc))
  166. throw new TypeError('malformed base64.');
  167. asc += '=='.slice(2 - (asc.length & 3));
  168. let u24, bin = '', r1, r2;
  169. for (let i = 0; i < asc.length;) {
  170. u24 = b64tab[asc.charAt(i++)] << 18
  171. | b64tab[asc.charAt(i++)] << 12
  172. | (r1 = b64tab[asc.charAt(i++)]) << 6
  173. | (r2 = b64tab[asc.charAt(i++)]);
  174. bin += r1 === 64 ? _fromCC(u24 >> 16 & 255)
  175. : r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255)
  176. : _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255);
  177. }
  178. return bin;
  179. };
  180. /**
  181. * does what `window.atob` of web browsers do.
  182. * @param {String} asc Base64-encoded string
  183. * @returns {string} binary string
  184. */
  185. const _atob = _hasatob ? (asc) => atob(_tidyB64(asc))
  186. : _hasBuffer ? (asc) => Buffer.from(asc, 'base64').toString('binary')
  187. : atobPolyfill;
  188. //
  189. const _toUint8Array = _hasBuffer
  190. ? (a) => _U8Afrom(Buffer.from(a, 'base64'))
  191. : (a) => _U8Afrom(_atob(a), c => c.charCodeAt(0));
  192. /**
  193. * converts a Base64 string to a Uint8Array.
  194. */
  195. const toUint8Array = (a) => _toUint8Array(_unURI(a));
  196. //
  197. const _decode = _hasBuffer
  198. ? (a) => Buffer.from(a, 'base64').toString('utf8')
  199. : _TD
  200. ? (a) => _TD.decode(_toUint8Array(a))
  201. : (a) => btou(_atob(a));
  202. const _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/'));
  203. /**
  204. * converts a Base64 string to a UTF-8 string.
  205. * @param {String} src Base64 string. Both normal and URL-safe are supported
  206. * @returns {string} UTF-8 string
  207. */
  208. const decode = (src) => _decode(_unURI(src));
  209. /**
  210. * check if a value is a valid Base64 string
  211. * @param {String} src a value to check
  212. */
  213. const isValid = (src) => {
  214. if (typeof src !== 'string')
  215. return false;
  216. const s = src.replace(/\s+/g, '').replace(/={0,2}$/, '');
  217. return !/[^\s0-9a-zA-Z\+/]/.test(s) || !/[^\s0-9a-zA-Z\-_]/.test(s);
  218. };
  219. //
  220. const _noEnum = (v) => {
  221. return {
  222. value: v, enumerable: false, writable: true, configurable: true
  223. };
  224. };
  225. /**
  226. * extend String.prototype with relevant methods
  227. */
  228. const extendString = function () {
  229. const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body));
  230. _add('fromBase64', function () { return decode(this); });
  231. _add('toBase64', function (urlsafe) { return encode(this, urlsafe); });
  232. _add('toBase64URI', function () { return encode(this, true); });
  233. _add('toBase64URL', function () { return encode(this, true); });
  234. _add('toUint8Array', function () { return toUint8Array(this); });
  235. };
  236. /**
  237. * extend Uint8Array.prototype with relevant methods
  238. */
  239. const extendUint8Array = function () {
  240. const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body));
  241. _add('toBase64', function (urlsafe) { return fromUint8Array(this, urlsafe); });
  242. _add('toBase64URI', function () { return fromUint8Array(this, true); });
  243. _add('toBase64URL', function () { return fromUint8Array(this, true); });
  244. };
  245. /**
  246. * extend Builtin prototypes with relevant methods
  247. */
  248. const extendBuiltins = () => {
  249. extendString();
  250. extendUint8Array();
  251. };
  252. const gBase64 = {
  253. version: version,
  254. VERSION: VERSION,
  255. atob: _atob,
  256. atobPolyfill: atobPolyfill,
  257. btoa: _btoa,
  258. btoaPolyfill: btoaPolyfill,
  259. fromBase64: decode,
  260. toBase64: encode,
  261. encode: encode,
  262. encodeURI: encodeURI,
  263. encodeURL: encodeURI,
  264. utob: utob,
  265. btou: btou,
  266. decode: decode,
  267. isValid: isValid,
  268. fromUint8Array: fromUint8Array,
  269. toUint8Array: toUint8Array,
  270. extendString: extendString,
  271. extendUint8Array: extendUint8Array,
  272. extendBuiltins: extendBuiltins,
  273. };
  274. // makecjs:CUT //
  275. export { version };
  276. export { VERSION };
  277. export { _atob as atob };
  278. export { atobPolyfill };
  279. export { _btoa as btoa };
  280. export { btoaPolyfill };
  281. export { decode as fromBase64 };
  282. export { encode as toBase64 };
  283. export { utob };
  284. export { encode };
  285. export { encodeURI };
  286. export { encodeURI as encodeURL };
  287. export { btou };
  288. export { decode };
  289. export { isValid };
  290. export { fromUint8Array };
  291. export { toUint8Array };
  292. export { extendString };
  293. export { extendUint8Array };
  294. export { extendBuiltins };
  295. // and finally,
  296. export { gBase64 as Base64 };