// Copyright 2011 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Wrappers for the HTML5 File API. These wrappers closely mirror16* the underlying APIs, but use Closure-style events and Deferred return values.17* Their existence also makes it possible to mock the FileSystem API for testing18* in browsers that don't support it natively.19*20* When adding public functions to anything under this namespace, be sure to add21* its mock counterpart to goog.testing.fs.22*23*/2425goog.provide('goog.fs');2627goog.require('goog.array');28goog.require('goog.async.Deferred');29goog.require('goog.fs.Error');30goog.require('goog.fs.FileReader');31goog.require('goog.fs.FileSystemImpl');32goog.require('goog.fs.url');33goog.require('goog.userAgent');343536/**37* Get a wrapped FileSystem object.38*39* @param {goog.fs.FileSystemType_} type The type of the filesystem to get.40* @param {number} size The size requested for the filesystem, in bytes.41* @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an42* error occurs, the errback is called with a {@link goog.fs.Error}.43* @private44*/45goog.fs.get_ = function(type, size) {46var requestFileSystem =47goog.global.requestFileSystem || goog.global.webkitRequestFileSystem;4849if (!goog.isFunction(requestFileSystem)) {50return goog.async.Deferred.fail(new Error('File API unsupported'));51}5253var d = new goog.async.Deferred();54requestFileSystem(55type, size, function(fs) { d.callback(new goog.fs.FileSystemImpl(fs)); },56function(err) {57d.errback(new goog.fs.Error(err, 'requesting filesystem'));58});59return d;60};616263/**64* The two types of filesystem.65*66* @enum {number}67* @private68*/69goog.fs.FileSystemType_ = {70/**71* A temporary filesystem may be deleted by the user agent at its discretion.72*/73TEMPORARY: 0,74/**75* A persistent filesystem will never be deleted without the user's or76* application's authorization.77*/78PERSISTENT: 179};808182/**83* Returns a temporary FileSystem object. A temporary filesystem may be deleted84* by the user agent at its discretion.85*86* @param {number} size The size requested for the filesystem, in bytes.87* @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an88* error occurs, the errback is called with a {@link goog.fs.Error}.89*/90goog.fs.getTemporary = function(size) {91return goog.fs.get_(goog.fs.FileSystemType_.TEMPORARY, size);92};939495/**96* Returns a persistent FileSystem object. A persistent filesystem will never be97* deleted without the user's or application's authorization.98*99* @param {number} size The size requested for the filesystem, in bytes.100* @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an101* error occurs, the errback is called with a {@link goog.fs.Error}.102*/103goog.fs.getPersistent = function(size) {104return goog.fs.get_(goog.fs.FileSystemType_.PERSISTENT, size);105};106107108/**109* Creates a blob URL for a blob object.110* Throws an error if the browser does not support Object Urls.111*112* TODO(user): Update references to this method to use113* goog.fs.url.createObjectUrl instead.114*115* @param {!Blob} blob The object for which to create the URL.116* @return {string} The URL for the object.117*/118goog.fs.createObjectUrl = function(blob) {119return goog.fs.url.createObjectUrl(blob);120};121122123/**124* Revokes a URL created by {@link goog.fs.createObjectUrl}.125* Throws an error if the browser does not support Object Urls.126*127* TODO(user): Update references to this method to use128* goog.fs.url.revokeObjectUrl instead.129*130* @param {string} url The URL to revoke.131*/132goog.fs.revokeObjectUrl = function(url) {133goog.fs.url.revokeObjectUrl(url);134};135136137/**138* Checks whether this browser supports Object Urls. If not, calls to139* createObjectUrl and revokeObjectUrl will result in an error.140*141* TODO(user): Update references to this method to use142* goog.fs.url.browserSupportsObjectUrls instead.143*144* @return {boolean} True if this browser supports Object Urls.145*/146goog.fs.browserSupportsObjectUrls = function() {147return goog.fs.url.browserSupportsObjectUrls();148};149150151/**152* Concatenates one or more values together and converts them to a Blob.153*154* @param {...(string|!Blob|!ArrayBuffer)} var_args The values that will make up155* the resulting blob.156* @return {!Blob} The blob.157*/158goog.fs.getBlob = function(var_args) {159var BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;160161if (goog.isDef(BlobBuilder)) {162var bb = new BlobBuilder();163for (var i = 0; i < arguments.length; i++) {164bb.append(arguments[i]);165}166return bb.getBlob();167} else {168return goog.fs.getBlobWithProperties(goog.array.toArray(arguments));169}170};171172173/**174* Creates a blob with the given properties.175* See https://developer.mozilla.org/en-US/docs/Web/API/Blob for more details.176*177* @param {Array<string|!Blob>} parts The values that will make up the178* resulting blob.179* @param {string=} opt_type The MIME type of the Blob.180* @param {string=} opt_endings Specifies how strings containing newlines are to181* be written out.182* @return {!Blob} The blob.183*/184goog.fs.getBlobWithProperties = function(parts, opt_type, opt_endings) {185var BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;186187if (goog.isDef(BlobBuilder)) {188var bb = new BlobBuilder();189for (var i = 0; i < parts.length; i++) {190bb.append(parts[i], opt_endings);191}192return bb.getBlob(opt_type);193} else if (goog.isDef(goog.global.Blob)) {194var properties = {};195if (opt_type) {196properties['type'] = opt_type;197}198if (opt_endings) {199properties['endings'] = opt_endings;200}201return new Blob(parts, properties);202} else {203throw Error('This browser doesn\'t seem to support creating Blobs');204}205};206207208/**209* Converts a Blob or a File into a string. This should only be used when the210* blob is known to be small.211*212* @param {!Blob} blob The blob to convert.213* @param {string=} opt_encoding The name of the encoding to use.214* @return {!goog.async.Deferred} The deferred string. If an error occurrs, the215* errback is called with a {@link goog.fs.Error}.216* @deprecated Use {@link goog.fs.FileReader.readAsText} instead.217*/218goog.fs.blobToString = function(blob, opt_encoding) {219return goog.fs.FileReader.readAsText(blob, opt_encoding);220};221222223/**224* Slices the blob. The returned blob contains data from the start byte225* (inclusive) till the end byte (exclusive). Negative indices can be used226* to count bytes from the end of the blob (-1 == blob.size - 1). Indices227* are always clamped to blob range. If end is omitted, all the data till228* the end of the blob is taken.229*230* @param {!Blob} blob The blob to be sliced.231* @param {number} start Index of the starting byte.232* @param {number=} opt_end Index of the ending byte.233* @return {Blob} The blob slice or null if not supported.234*/235goog.fs.sliceBlob = function(blob, start, opt_end) {236if (!goog.isDef(opt_end)) {237opt_end = blob.size;238}239if (blob.webkitSlice) {240// Natively accepts negative indices, clamping to the blob range and241// range end is optional. See http://trac.webkit.org/changeset/83873242return blob.webkitSlice(start, opt_end);243} else if (blob.mozSlice) {244// Natively accepts negative indices, clamping to the blob range and245// range end is optional. See https://developer.mozilla.org/en/DOM/Blob246// and http://hg.mozilla.org/mozilla-central/rev/dae833f4d934247return blob.mozSlice(start, opt_end);248} else if (blob.slice) {249// Old versions of Firefox and Chrome use the original specification.250// Negative indices are not accepted, only range end is clamped and251// range end specification is obligatory.252// See http://www.w3.org/TR/2009/WD-FileAPI-20091117/253if ((goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('13.0')) ||254(goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('537.1'))) {255if (start < 0) {256start += blob.size;257}258if (start < 0) {259start = 0;260}261if (opt_end < 0) {262opt_end += blob.size;263}264if (opt_end < start) {265opt_end = start;266}267return blob.slice(start, opt_end - start);268}269// IE and the latest versions of Firefox and Chrome use the new270// specification. Natively accepts negative indices, clamping to the blob271// range and range end is optional.272// See http://dev.w3.org/2006/webapi/FileAPI/273return blob.slice(start, opt_end);274}275return null;276};277278279