Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

Blob.js 21KB

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