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