From 5a68bbfae28a843053c4d9a8cd7af57e6d95e1b8 Mon Sep 17 00:00:00 2001 From: Eli Grey Date: Thu, 14 Jul 2011 23:26:51 -0400 Subject: [PATCH] Initial commit --- BlobBuilder.js | 163 +++++++++++++++++++++++++++++++++++++++++++++ BlobBuilder.min.js | 2 + LICENSE.md | 30 +++++++++ README.md | 15 +++++ 4 files changed, 210 insertions(+) create mode 100644 BlobBuilder.js create mode 100644 BlobBuilder.min.js create mode 100644 LICENSE.md create mode 100644 README.md diff --git a/BlobBuilder.js b/BlobBuilder.js new file mode 100644 index 0000000..f61e85b --- /dev/null +++ b/BlobBuilder.js @@ -0,0 +1,163 @@ +/* BlobBuilder.js + * A BlobBuilder implementation. + * 2011-07-13 + * + * By Eli Grey, http://eligrey.com + * License: X11/MIT + * See 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/BlobBuilder.js/blob/master/BlobBuilder.js */ + +var BlobBuilder = BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || (function(view) { +"use strict"; +var + get_class = function(object) { + return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; + } + , FakeBlobBuilder = function(){ + this.data = []; + } + , FakeBlob = function(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 + , realURL = view.URL || view.webkitURL || view + , real_create_object_URL = realURL.createObjectURL + , real_revoke_object_URL = realURL.revokeObjectURL + , URL = realURL + , btoa = view.btoa + , atob = view.atob + , can_apply_typed_arrays = false + , can_apply_typed_arrays_test = function(pass) { + can_apply_typed_arrays = !pass; + } + + , ArrayBuffer = view.ArrayBuffer + , Uint8Array = view.Uint8Array +; +FakeBlobBuilder.fake = FB_proto.fake = true; +while (file_ex_code--) { + FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; +} +try { + if (Uint8Array) { + can_apply_typed_arrays_test.apply(0, new Uint8Array(1)); + } +} catch (ex) {} +// Create URL if it doesn't exist or to fix a bug in Firefox where URL's properties are +// reset after the page finishes loading. +if (!realURL.createObjectURL || get_class(realURL) === "MozURLProperty") { + URL = view.URL = {}; +} +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(realURL, blob); + } +}; +URL.revokeObjectURL = function(object_url) { + if (object_url.substring(0, 5) !== "data:" && real_revoke_object_url) { + real_revoke_object_url.call(realURL, object_url); + } +}; +FBB_proto.append = function(data/*, endings*/) { + var bb = this.data; + // decode data to a binary string + if (Uint8Array && data instanceof ArrayBuffer) { + if (can_apply_typed_arrays) { + bb.push(String.fromCharCode.apply(String, new Uint8Array(data))); + } else { + var + str = "" + , buf = new Uint8Array(data) + , i = 0 + , buf_len = buf.length + ; + for (; i < buf_len; i++) { + str += String.fromCharCode(buf[i]); + } + } + } 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]"; +}; +return FakeBlobBuilder; +}(self)); \ No newline at end of file diff --git a/BlobBuilder.min.js b/BlobBuilder.min.js new file mode 100644 index 0000000..763a1ff --- /dev/null +++ b/BlobBuilder.min.js @@ -0,0 +1,2 @@ +/*! @source http://purl.eligrey.com/github/BlobBuilder.js/blob/master/BlobBuilder.js */ +var BlobBuilder=BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||(function(j){"use strict";var c=function(v){return Object.prototype.toString.call(v).match(/^\[object\s(.*)\]$/)[1]},u=function(){this.data=[]},t=function(x,v,w){this.data=x;this.size=x.length;this.type=v;this.encoding=w},k=u.prototype,s=t.prototype,n=j.FileReaderSync,a=function(v){this.code=this[this.name=v]},l=("NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR").split(" "),r=l.length,o=j.URL||j.webkitURL||j,p=o.createObjectURL,b=o.revokeObjectURL,e=o,i=j.btoa,f=j.atob,m=false,h=function(v){m=!v},d=j.ArrayBuffer,g=j.Uint8Array;u.fake=s.fake=true;while(r--){a.prototype[l[r]]=r+1}try{if(g){h.apply(0,new g(1))}}catch(q){}if(!o.createObjectURL||c(o)==="MozURLProperty"){e=j.URL={}}e.createObjectURL=function(w){var x=w.type,v;if(x===null){x="application/octet-stream"}if(w instanceof t){v="data:"+x;if(w.encoding==="base64"){return v+";base64,"+w.data}else{if(w.encoding==="URI"){return v+","+decodeURIComponent(w.data)}}if(i){return v+";base64,"+i(w.data)}else{return v+","+encodeURIComponent(w.data)}}else{if(real_create_object_url){return real_create_object_url.call(o,w)}}};e.revokeObjectURL=function(v){if(v.substring(0,5)!=="data:"&&real_revoke_object_url){real_revoke_object_url.call(o,v)}};k.append=function(z){var B=this.data;if(g&&z instanceof d){if(m){B.push(String.fromCharCode.apply(String,new g(z)))}else{var A="",w=new g(z),x=0,y=w.length;for(;x1?v:this.data.length),x,this.encoding)};s.toString=function(){return"[object Blob]"};return u}(self)); \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..7eb56b9 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,30 @@ +This software is licensed under the MIT/X11 license. + +MIT/X11 license +--------------- + +Copyright © 2011 [Eli Grey][1]. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + + [1]: http://eligrey.com \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..cb7e874 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +BlobBuilder.js +============== + +BlobBuilder.js implements the W3C [`BlobBuilder`][1] interface in browsers that do +not natively support it. + +Limitations +----------- + +You can not append native blobs to a BlobBuilder.js `BlobBuilder` unless the script is in +a web worker thread, as the necessary `FileReaderSync` interface for reading native blobs +is limited to web worker threads only. + + + [1]: http://www.w3.org/TR/file-writer-api/#the-blobbuilder-interface \ No newline at end of file