_blob.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. /* eslint-disable */
  2. /**
  3. * Blob.js
  4. * A Blob, File, FileReader & URL implementation.
  5. * 2019-04-19
  6. *
  7. * By Eli Grey, http://eligrey.com
  8. * By Jimmy Wärting, https://github.com/jimmywarting
  9. * License: MIT
  10. * See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
  11. */
  12. (function() {
  13. var global = typeof window === 'object'
  14. ? window : typeof self === 'object'
  15. ? self : this
  16. var BlobBuilder = global.BlobBuilder ||
  17. global.WebKitBlobBuilder ||
  18. global.MSBlobBuilder ||
  19. global.MozBlobBuilder
  20. global.URL = global.URL || global.webkitURL || function(href, a) {
  21. a = document.createElement('a')
  22. a.href = href
  23. return a
  24. }
  25. var origBlob = global.Blob
  26. var createObjectURL = URL.createObjectURL
  27. var revokeObjectURL = URL.revokeObjectURL
  28. var strTag = global.Symbol && global.Symbol.toStringTag
  29. var blobSupported = false
  30. var blobSupportsArrayBufferView = false
  31. var arrayBufferSupported = !!global.ArrayBuffer
  32. var blobBuilderSupported = BlobBuilder &&
  33. BlobBuilder.prototype.append &&
  34. BlobBuilder.prototype.getBlob
  35. try {
  36. // Check if Blob constructor is supported
  37. blobSupported = new Blob(['ä']).size === 2
  38. // Check if Blob constructor supports ArrayBufferViews
  39. // Fails in Safari 6, so we need to map to ArrayBuffers there.
  40. blobSupportsArrayBufferView = new Blob([new Uint8Array([1, 2])]).size === 2
  41. } catch (e) {}
  42. /**
  43. * Helper function that maps ArrayBufferViews to ArrayBuffers
  44. * Used by BlobBuilder constructor and old browsers that didn't
  45. * support it in the Blob constructor.
  46. */
  47. function mapArrayBufferViews(ary) {
  48. return ary.map(function(chunk) {
  49. if (chunk.buffer instanceof ArrayBuffer) {
  50. var buf = chunk.buffer
  51. // if this is a subarray, make a copy so we only
  52. // include the subarray region from the underlying buffer
  53. if (chunk.byteLength !== buf.byteLength) {
  54. var copy = new Uint8Array(chunk.byteLength)
  55. copy.set(new Uint8Array(buf, chunk.byteOffset, chunk.byteLength))
  56. buf = copy.buffer
  57. }
  58. return buf
  59. }
  60. return chunk
  61. })
  62. }
  63. function BlobBuilderConstructor(ary, options) {
  64. options = options || {}
  65. var bb = new BlobBuilder()
  66. mapArrayBufferViews(ary).forEach(function(part) {
  67. bb.append(part)
  68. })
  69. return options.type ? bb.getBlob(options.type) : bb.getBlob()
  70. }
  71. function BlobConstructor(ary, options) {
  72. return new origBlob(mapArrayBufferViews(ary), options || {})
  73. }
  74. if (global.Blob) {
  75. BlobBuilderConstructor.prototype = Blob.prototype
  76. BlobConstructor.prototype = Blob.prototype
  77. }
  78. /** ******************************************************/
  79. /* String Encoder fallback */
  80. /** ******************************************************/
  81. function stringEncode(string) {
  82. var pos = 0
  83. var len = string.length
  84. var out = []
  85. var Arr = global.Uint8Array || Array // Use byte array when possible
  86. var at = 0 // output position
  87. var tlen = Math.max(32, len + (len >> 1) + 7) // 1.5x size
  88. var target = new Arr((tlen >> 3) << 3) // ... but at 8 byte offset
  89. while (pos < len) {
  90. var value = string.charCodeAt(pos++)
  91. if (value >= 0xd800 && value <= 0xdbff) {
  92. // high surrogate
  93. if (pos < len) {
  94. var extra = string.charCodeAt(pos)
  95. if ((extra & 0xfc00) === 0xdc00) {
  96. ++pos
  97. value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000
  98. }
  99. }
  100. if (value >= 0xd800 && value <= 0xdbff) {
  101. continue // drop lone surrogate
  102. }
  103. }
  104. // expand the buffer if we couldn't write 4 bytes
  105. if (at + 4 > target.length) {
  106. tlen += 8 // minimum extra
  107. tlen *= (1.0 + (pos / string.length) * 2) // take 2x the remaining
  108. tlen = (tlen >> 3) << 3 // 8 byte offset
  109. const update = new Uint8Array(tlen)
  110. update.set(target)
  111. target = update
  112. }
  113. if ((value & 0xffffff80) === 0) { // 1-byte
  114. target[at++] = value // ASCII
  115. continue
  116. } else if ((value & 0xfffff800) === 0) { // 2-byte
  117. target[at++] = ((value >> 6) & 0x1f) | 0xc0
  118. } else if ((value & 0xffff0000) === 0) { // 3-byte
  119. target[at++] = ((value >> 12) & 0x0f) | 0xe0
  120. target[at++] = ((value >> 6) & 0x3f) | 0x80
  121. } else if ((value & 0xffe00000) === 0) { // 4-byte
  122. target[at++] = ((value >> 18) & 0x07) | 0xf0
  123. target[at++] = ((value >> 12) & 0x3f) | 0x80
  124. target[at++] = ((value >> 6) & 0x3f) | 0x80
  125. } else {
  126. continue
  127. }
  128. target[at++] = (value & 0x3f) | 0x80
  129. }
  130. return target.slice(0, at)
  131. }
  132. /** ******************************************************/
  133. /* String Decoder fallback */
  134. /** ******************************************************/
  135. function stringDecode(buf) {
  136. var end = buf.length
  137. var res = []
  138. var i = 0
  139. while (i < end) {
  140. var firstByte = buf[i]
  141. var codePoint = null
  142. var bytesPerSequence = (firstByte > 0xEF) ? 4
  143. : (firstByte > 0xDF) ? 3
  144. : (firstByte > 0xBF) ? 2
  145. : 1
  146. if (i + bytesPerSequence <= end) {
  147. var secondByte, thirdByte, fourthByte, tempCodePoint
  148. switch (bytesPerSequence) {
  149. case 1:
  150. if (firstByte < 0x80) {
  151. codePoint = firstByte
  152. }
  153. break
  154. case 2:
  155. secondByte = buf[i + 1]
  156. if ((secondByte & 0xC0) === 0x80) {
  157. tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
  158. if (tempCodePoint > 0x7F) {
  159. codePoint = tempCodePoint
  160. }
  161. }
  162. break
  163. case 3:
  164. secondByte = buf[i + 1]
  165. thirdByte = buf[i + 2]
  166. if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
  167. tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
  168. if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
  169. codePoint = tempCodePoint
  170. }
  171. }
  172. break
  173. case 4:
  174. secondByte = buf[i + 1]
  175. thirdByte = buf[i + 2]
  176. fourthByte = buf[i + 3]
  177. if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
  178. tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
  179. if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
  180. codePoint = tempCodePoint
  181. }
  182. }
  183. }
  184. }
  185. if (codePoint === null) {
  186. // we did not generate a valid codePoint so insert a
  187. // replacement char (U+FFFD) and advance only 1 byte
  188. codePoint = 0xFFFD
  189. bytesPerSequence = 1
  190. } else if (codePoint > 0xFFFF) {
  191. // encode to utf16 (surrogate pair dance)
  192. codePoint -= 0x10000
  193. res.push(codePoint >>> 10 & 0x3FF | 0xD800)
  194. codePoint = 0xDC00 | codePoint & 0x3FF
  195. }
  196. res.push(codePoint)
  197. i += bytesPerSequence
  198. }
  199. var len = res.length
  200. var str = ''
  201. var i = 0
  202. while (i < len) {
  203. str += String.fromCharCode.apply(String, res.slice(i, i += 0x1000))
  204. }
  205. return str
  206. }
  207. // string -> buffer
  208. var textEncode = typeof TextEncoder === 'function'
  209. ? TextEncoder.prototype.encode.bind(new TextEncoder())
  210. : stringEncode
  211. // buffer -> string
  212. var textDecode = typeof TextDecoder === 'function'
  213. ? TextDecoder.prototype.decode.bind(new TextDecoder())
  214. : stringDecode
  215. function FakeBlobBuilder() {
  216. function isDataView(obj) {
  217. return obj && DataView.prototype.isPrototypeOf(obj)
  218. }
  219. function bufferClone(buf) {
  220. var view = new Array(buf.byteLength)
  221. var array = new Uint8Array(buf)
  222. var i = view.length
  223. while (i--) {
  224. view[i] = array[i]
  225. }
  226. return view
  227. }
  228. function array2base64(input) {
  229. var byteToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
  230. var output = []
  231. for (var i = 0; i < input.length; i += 3) {
  232. var byte1 = input[i]
  233. var haveByte2 = i + 1 < input.length
  234. var byte2 = haveByte2 ? input[i + 1] : 0
  235. var haveByte3 = i + 2 < input.length
  236. var byte3 = haveByte3 ? input[i + 2] : 0
  237. var outByte1 = byte1 >> 2
  238. var outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4)
  239. var outByte3 = ((byte2 & 0x0F) << 2) | (byte3 >> 6)
  240. var outByte4 = byte3 & 0x3F
  241. if (!haveByte3) {
  242. outByte4 = 64
  243. if (!haveByte2) {
  244. outByte3 = 64
  245. }
  246. }
  247. output.push(
  248. byteToCharMap[outByte1], byteToCharMap[outByte2],
  249. byteToCharMap[outByte3], byteToCharMap[outByte4]
  250. )
  251. }
  252. return output.join('')
  253. }
  254. var create = Object.create || function(a) {
  255. function c() {}
  256. c.prototype = a
  257. return new c()
  258. }
  259. if (arrayBufferSupported) {
  260. var viewClasses = [
  261. '[object Int8Array]',
  262. '[object Uint8Array]',
  263. '[object Uint8ClampedArray]',
  264. '[object Int16Array]',
  265. '[object Uint16Array]',
  266. '[object Int32Array]',
  267. '[object Uint32Array]',
  268. '[object Float32Array]',
  269. '[object Float64Array]'
  270. ]
  271. var isArrayBufferView = ArrayBuffer.isView || function(obj) {
  272. return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
  273. }
  274. }
  275. function concatTypedarrays(chunks) {
  276. var size = 0
  277. var i = chunks.length
  278. while (i--) { size += chunks[i].length }
  279. var b = new Uint8Array(size)
  280. var offset = 0
  281. for (i = 0, l = chunks.length; i < l; i++) {
  282. var chunk = chunks[i]
  283. b.set(chunk, offset)
  284. offset += chunk.byteLength || chunk.length
  285. }
  286. return b
  287. }
  288. /** ******************************************************/
  289. /* Blob constructor */
  290. /** ******************************************************/
  291. function Blob(chunks, opts) {
  292. chunks = chunks || []
  293. opts = opts == null ? {} : opts
  294. for (var i = 0, len = chunks.length; i < len; i++) {
  295. var chunk = chunks[i]
  296. if (chunk instanceof Blob) {
  297. chunks[i] = chunk._buffer
  298. } else if (typeof chunk === 'string') {
  299. chunks[i] = textEncode(chunk)
  300. } else if (arrayBufferSupported && (ArrayBuffer.prototype.isPrototypeOf(chunk) || isArrayBufferView(chunk))) {
  301. chunks[i] = bufferClone(chunk)
  302. } else if (arrayBufferSupported && isDataView(chunk)) {
  303. chunks[i] = bufferClone(chunk.buffer)
  304. } else {
  305. chunks[i] = textEncode(String(chunk))
  306. }
  307. }
  308. this._buffer = global.Uint8Array
  309. ? concatTypedarrays(chunks)
  310. : [].concat.apply([], chunks)
  311. this.size = this._buffer.length
  312. this.type = opts.type || ''
  313. if (/[^\u0020-\u007E]/.test(this.type)) {
  314. this.type = ''
  315. } else {
  316. this.type = this.type.toLowerCase()
  317. }
  318. }
  319. Blob.prototype.arrayBuffer = function() {
  320. return Promise.resolve(this._buffer)
  321. }
  322. Blob.prototype.text = function() {
  323. return Promise.resolve(textDecode(this._buffer))
  324. }
  325. Blob.prototype.slice = function(start, end, type) {
  326. var slice = this._buffer.slice(start || 0, end || this._buffer.length)
  327. return new Blob([slice], { type: type })
  328. }
  329. Blob.prototype.toString = function() {
  330. return '[object Blob]'
  331. }
  332. /** ******************************************************/
  333. /* File constructor */
  334. /** ******************************************************/
  335. function File(chunks, name, opts) {
  336. opts = opts || {}
  337. var a = Blob.call(this, chunks, opts) || this
  338. a.name = name.replace(/\//g, ':')
  339. a.lastModifiedDate = opts.lastModified ? new Date(opts.lastModified) : new Date()
  340. a.lastModified = +a.lastModifiedDate
  341. return a
  342. }
  343. File.prototype = create(Blob.prototype)
  344. File.prototype.constructor = File
  345. if (Object.setPrototypeOf) {
  346. Object.setPrototypeOf(File, Blob)
  347. } else {
  348. try { File.__proto__ = Blob } catch (e) {}
  349. }
  350. File.prototype.toString = function() {
  351. return '[object File]'
  352. }
  353. /** ******************************************************/
  354. /* FileReader constructor */
  355. /** ******************************************************/
  356. function FileReader() {
  357. if (!(this instanceof FileReader)) {
  358. throw new TypeError("Failed to construct 'FileReader': Please use the 'new' operator, this DOM object constructor cannot be called as a function.")
  359. }
  360. var delegate = document.createDocumentFragment()
  361. this.addEventListener = delegate.addEventListener
  362. this.dispatchEvent = function(evt) {
  363. var local = this['on' + evt.type]
  364. if (typeof local === 'function') local(evt)
  365. delegate.dispatchEvent(evt)
  366. }
  367. this.removeEventListener = delegate.removeEventListener
  368. }
  369. function _read(fr, blob, kind) {
  370. if (!(blob instanceof Blob)) {
  371. throw new TypeError("Failed to execute '" + kind + "' on 'FileReader': parameter 1 is not of type 'Blob'.")
  372. }
  373. fr.result = ''
  374. setTimeout(function() {
  375. this.readyState = FileReader.LOADING
  376. fr.dispatchEvent(new Event('load'))
  377. fr.dispatchEvent(new Event('loadend'))
  378. })
  379. }
  380. FileReader.EMPTY = 0
  381. FileReader.LOADING = 1
  382. FileReader.DONE = 2
  383. FileReader.prototype.error = null
  384. FileReader.prototype.onabort = null
  385. FileReader.prototype.onerror = null
  386. FileReader.prototype.onload = null
  387. FileReader.prototype.onloadend = null
  388. FileReader.prototype.onloadstart = null
  389. FileReader.prototype.onprogress = null
  390. FileReader.prototype.readAsDataURL = function(blob) {
  391. _read(this, blob, 'readAsDataURL')
  392. this.result = 'data:' + blob.type + ';base64,' + array2base64(blob._buffer)
  393. }
  394. FileReader.prototype.readAsText = function(blob) {
  395. _read(this, blob, 'readAsText')
  396. this.result = textDecode(blob._buffer)
  397. }
  398. FileReader.prototype.readAsArrayBuffer = function(blob) {
  399. _read(this, blob, 'readAsText')
  400. // return ArrayBuffer when possible
  401. this.result = (blob._buffer.buffer || blob._buffer).slice()
  402. }
  403. FileReader.prototype.abort = function() {}
  404. /** ******************************************************/
  405. /* URL */
  406. /** ******************************************************/
  407. URL.createObjectURL = function(blob) {
  408. return blob instanceof Blob
  409. ? 'data:' + blob.type + ';base64,' + array2base64(blob._buffer)
  410. : createObjectURL.call(URL, blob)
  411. }
  412. URL.revokeObjectURL = function(url) {
  413. revokeObjectURL && revokeObjectURL.call(URL, url)
  414. }
  415. /** ******************************************************/
  416. /* XHR */
  417. /** ******************************************************/
  418. var _send = global.XMLHttpRequest && global.XMLHttpRequest.prototype.send
  419. if (_send) {
  420. XMLHttpRequest.prototype.send = function(data) {
  421. if (data instanceof Blob) {
  422. this.setRequestHeader('Content-Type', data.type)
  423. _send.call(this, textDecode(data._buffer))
  424. } else {
  425. _send.call(this, data)
  426. }
  427. }
  428. }
  429. global.FileReader = FileReader
  430. global.File = File
  431. global.Blob = Blob
  432. }
  433. function fixFileAndXHR() {
  434. var isIE = !!global.ActiveXObject || (
  435. '-ms-scroll-limit' in document.documentElement.style &&
  436. '-ms-ime-align' in document.documentElement.style
  437. )
  438. // Monkey patched
  439. // IE don't set Content-Type header on XHR whose body is a typed Blob
  440. // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6047383
  441. var _send = global.XMLHttpRequest && global.XMLHttpRequest.prototype.send
  442. if (isIE && _send) {
  443. XMLHttpRequest.prototype.send = function(data) {
  444. if (data instanceof Blob) {
  445. this.setRequestHeader('Content-Type', data.type)
  446. _send.call(this, data)
  447. } else {
  448. _send.call(this, data)
  449. }
  450. }
  451. }
  452. try {
  453. new File([], '')
  454. } catch (e) {
  455. try {
  456. var klass = new Function('class File extends Blob {' +
  457. 'constructor(chunks, name, opts) {' +
  458. 'opts = opts || {};' +
  459. 'super(chunks, opts || {});' +
  460. 'this.name = name.replace(/\//g, ":");' +
  461. 'this.lastModifiedDate = opts.lastModified ? new Date(opts.lastModified) : new Date();' +
  462. 'this.lastModified = +this.lastModifiedDate;' +
  463. '}};' +
  464. 'return new File([], ""), File'
  465. )()
  466. global.File = klass
  467. } catch (e) {
  468. var klass = function(b, d, c) {
  469. var blob = new Blob(b, c)
  470. var t = c && void 0 !== c.lastModified ? new Date(c.lastModified) : new Date()
  471. blob.name = d.replace(/\//g, ':')
  472. blob.lastModifiedDate = t
  473. blob.lastModified = +t
  474. blob.toString = function() {
  475. return '[object File]'
  476. }
  477. if (strTag) {
  478. blob[strTag] = 'File'
  479. }
  480. return blob
  481. }
  482. global.File = klass
  483. }
  484. }
  485. }
  486. if (blobSupported) {
  487. fixFileAndXHR()
  488. global.Blob = blobSupportsArrayBufferView ? global.Blob : BlobConstructor
  489. } else if (blobBuilderSupported) {
  490. fixFileAndXHR()
  491. global.Blob = BlobBuilderConstructor
  492. } else {
  493. FakeBlobBuilder()
  494. }
  495. if (strTag) {
  496. File.prototype[strTag] = 'File'
  497. Blob.prototype[strTag] = 'Blob'
  498. FileReader.prototype[strTag] = 'FileReader'
  499. }
  500. var blob = global.Blob.prototype
  501. var stream
  502. function promisify(obj) {
  503. return new Promise(function(resolve, reject) {
  504. obj.onload =
  505. obj.onerror = function(evt) {
  506. obj.onload =
  507. obj.onerror = null
  508. evt.type === 'load'
  509. ? resolve(obj.result || obj)
  510. : reject(new Error('Failed to read the blob/file'))
  511. }
  512. })
  513. }
  514. try {
  515. new ReadableStream({ type: 'bytes' })
  516. stream = function stream() {
  517. var position = 0
  518. var blob = this
  519. return new ReadableStream({
  520. type: 'bytes',
  521. autoAllocateChunkSize: 524288,
  522. pull: function(controller) {
  523. var v = controller.byobRequest.view
  524. var chunk = blob.slice(position, position + v.byteLength)
  525. return chunk.arrayBuffer()
  526. .then(function(buffer) {
  527. var uint8array = new Uint8Array(buffer)
  528. var bytesRead = uint8array.byteLength
  529. position += bytesRead
  530. v.set(uint8array)
  531. controller.byobRequest.respond(bytesRead)
  532. if (position >= blob.size) { controller.close() }
  533. })
  534. }
  535. })
  536. }
  537. } catch (e) {
  538. try {
  539. new ReadableStream({})
  540. stream = function stream(blob) {
  541. var position = 0
  542. var blob = this
  543. return new ReadableStream({
  544. pull: function(controller) {
  545. var chunk = blob.slice(position, position + 524288)
  546. return chunk.arrayBuffer().then(function(buffer) {
  547. position += buffer.byteLength
  548. var uint8array = new Uint8Array(buffer)
  549. controller.enqueue(uint8array)
  550. if (position == blob.size) { controller.close() }
  551. })
  552. }
  553. })
  554. }
  555. } catch (e) {
  556. try {
  557. new Response('').body.getReader().read()
  558. stream = function stream() {
  559. return (new Response(this)).body
  560. }
  561. } catch (e) {
  562. stream = function stream() {
  563. throw new Error('Include https://github.com/MattiasBuelens/web-streams-polyfill')
  564. }
  565. }
  566. }
  567. }
  568. if (!blob.arrayBuffer) {
  569. blob.arrayBuffer = function arrayBuffer() {
  570. var fr = new FileReader()
  571. fr.readAsArrayBuffer(this)
  572. return promisify(fr)
  573. }
  574. }
  575. if (!blob.text) {
  576. blob.text = function text() {
  577. var fr = new FileReader()
  578. fr.readAsText(this)
  579. return promisify(fr)
  580. }
  581. }
  582. if (!blob.stream) {
  583. blob.stream = stream
  584. }
  585. })()