Spaces:
Running
Running
/* Blob.js | |
* A Blob implementation. | |
* 2014-07-24 | |
* | |
* By Eli Grey, http://eligrey.com | |
* By Devin Samarin, https://github.com/dsamarin | |
* License: X11/MIT | |
* See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md | |
*/ | |
/*global self, unescape */ | |
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, | |
plusplus: true */ | |
/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */ | |
(function (view) { | |
"use strict"; | |
view.URL = view.URL || view.webkitURL; | |
if (view.Blob && view.URL) { | |
try { | |
new Blob; | |
return; | |
} catch (e) {} | |
} | |
// Internally we use a BlobBuilder implementation to base Blob off of | |
// in order to support older browsers that only have BlobBuilder | |
var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) { | |
var | |
get_class = function(object) { | |
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; | |
} | |
, FakeBlobBuilder = function BlobBuilder() { | |
this.data = []; | |
} | |
, FakeBlob = function Blob(data, type, encoding) { | |
this.data = data; | |
this.size = data.length; | |
this.type = type; | |
this.encoding = encoding; | |
} | |
, FBB_proto = FakeBlobBuilder.prototype | |
, FB_proto = FakeBlob.prototype | |
, FileReaderSync = view.FileReaderSync | |
, FileException = function(type) { | |
this.code = this[this.name = type]; | |
} | |
, file_ex_codes = ( | |
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " | |
+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" | |
).split(" ") | |
, file_ex_code = file_ex_codes.length | |
, real_URL = view.URL || view.webkitURL || view | |
, real_create_object_URL = real_URL.createObjectURL | |
, real_revoke_object_URL = real_URL.revokeObjectURL | |
, URL = real_URL | |
, btoa = view.btoa | |
, atob = view.atob | |
, ArrayBuffer = view.ArrayBuffer | |
, Uint8Array = view.Uint8Array | |
, origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/ | |
; | |
FakeBlob.fake = FB_proto.fake = true; | |
while (file_ex_code--) { | |
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; | |
} | |
// Polyfill URL | |
if (!real_URL.createObjectURL) { | |
URL = view.URL = function(uri) { | |
var | |
uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a") | |
, uri_origin | |
; | |
uri_info.href = uri; | |
if (!("origin" in uri_info)) { | |
if (uri_info.protocol.toLowerCase() === "data:") { | |
uri_info.origin = null; | |
} else { | |
uri_origin = uri.match(origin); | |
uri_info.origin = uri_origin && uri_origin[1]; | |
} | |
} | |
return uri_info; | |
}; | |
} | |
URL.createObjectURL = function(blob) { | |
var | |
type = blob.type | |
, data_URI_header | |
; | |
if (type === null) { | |
type = "application/octet-stream"; | |
} | |
if (blob instanceof FakeBlob) { | |
data_URI_header = "data:" + type; | |
if (blob.encoding === "base64") { | |
return data_URI_header + ";base64," + blob.data; | |
} else if (blob.encoding === "URI") { | |
return data_URI_header + "," + decodeURIComponent(blob.data); | |
} if (btoa) { | |
return data_URI_header + ";base64," + btoa(blob.data); | |
} else { | |
return data_URI_header + "," + encodeURIComponent(blob.data); | |
} | |
} else if (real_create_object_URL) { | |
return real_create_object_URL.call(real_URL, blob); | |
} | |
}; | |
URL.revokeObjectURL = function(object_URL) { | |
if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { | |
real_revoke_object_URL.call(real_URL, object_URL); | |
} | |
}; | |
FBB_proto.append = function(data/*, endings*/) { | |
var bb = this.data; | |
// decode data to a binary string | |
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { | |
var | |
str = "" | |
, buf = new Uint8Array(data) | |
, i = 0 | |
, buf_len = buf.length | |
; | |
for (; i < buf_len; i++) { | |
str += String.fromCharCode(buf[i]); | |
} | |
bb.push(str); | |
} else if (get_class(data) === "Blob" || get_class(data) === "File") { | |
if (FileReaderSync) { | |
var fr = new FileReaderSync; | |
bb.push(fr.readAsBinaryString(data)); | |
} else { | |
// async FileReader won't work as BlobBuilder is sync | |
throw new FileException("NOT_READABLE_ERR"); | |
} | |
} else if (data instanceof FakeBlob) { | |
if (data.encoding === "base64" && atob) { | |
bb.push(atob(data.data)); | |
} else if (data.encoding === "URI") { | |
bb.push(decodeURIComponent(data.data)); | |
} else if (data.encoding === "raw") { | |
bb.push(data.data); | |
} | |
} else { | |
if (typeof data !== "string") { | |
data += ""; // convert unsupported types to strings | |
} | |
// decode UTF-16 to binary string | |
bb.push(unescape(encodeURIComponent(data))); | |
} | |
}; | |
FBB_proto.getBlob = function(type) { | |
if (!arguments.length) { | |
type = null; | |
} | |
return new FakeBlob(this.data.join(""), type, "raw"); | |
}; | |
FBB_proto.toString = function() { | |
return "[object BlobBuilder]"; | |
}; | |
FB_proto.slice = function(start, end, type) { | |
var args = arguments.length; | |
if (args < 3) { | |
type = null; | |
} | |
return new FakeBlob( | |
this.data.slice(start, args > 1 ? end : this.data.length) | |
, type | |
, this.encoding | |
); | |
}; | |
FB_proto.toString = function() { | |
return "[object Blob]"; | |
}; | |
FB_proto.close = function() { | |
this.size = 0; | |
delete this.data; | |
}; | |
return FakeBlobBuilder; | |
}(view)); | |
view.Blob = function(blobParts, options) { | |
var type = options ? (options.type || "") : ""; | |
var builder = new BlobBuilder(); | |
if (blobParts) { | |
for (var i = 0, len = blobParts.length; i < len; i++) { | |
builder.append(blobParts[i]); | |
} | |
} | |
return builder.getBlob(type); | |
}; | |
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this)); | |