fs.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. // Copyright 2011 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Wrappers for the HTML5 File API. These wrappers closely mirror
  16. * 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 testing
  18. * in browsers that don't support it natively.
  19. *
  20. * When adding public functions to anything under this namespace, be sure to add
  21. * its mock counterpart to goog.testing.fs.
  22. *
  23. */
  24. goog.provide('goog.fs');
  25. goog.require('goog.array');
  26. goog.require('goog.async.Deferred');
  27. goog.require('goog.fs.Error');
  28. goog.require('goog.fs.FileReader');
  29. goog.require('goog.fs.FileSystemImpl');
  30. goog.require('goog.fs.url');
  31. goog.require('goog.userAgent');
  32. /**
  33. * Get a wrapped FileSystem object.
  34. *
  35. * @param {goog.fs.FileSystemType_} type The type of the filesystem to get.
  36. * @param {number} size The size requested for the filesystem, in bytes.
  37. * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
  38. * error occurs, the errback is called with a {@link goog.fs.Error}.
  39. * @private
  40. */
  41. goog.fs.get_ = function(type, size) {
  42. var requestFileSystem =
  43. goog.global.requestFileSystem || goog.global.webkitRequestFileSystem;
  44. if (!goog.isFunction(requestFileSystem)) {
  45. return goog.async.Deferred.fail(new Error('File API unsupported'));
  46. }
  47. var d = new goog.async.Deferred();
  48. requestFileSystem(
  49. type, size, function(fs) { d.callback(new goog.fs.FileSystemImpl(fs)); },
  50. function(err) {
  51. d.errback(new goog.fs.Error(err, 'requesting filesystem'));
  52. });
  53. return d;
  54. };
  55. /**
  56. * The two types of filesystem.
  57. *
  58. * @enum {number}
  59. * @private
  60. */
  61. goog.fs.FileSystemType_ = {
  62. /**
  63. * A temporary filesystem may be deleted by the user agent at its discretion.
  64. */
  65. TEMPORARY: 0,
  66. /**
  67. * A persistent filesystem will never be deleted without the user's or
  68. * application's authorization.
  69. */
  70. PERSISTENT: 1
  71. };
  72. /**
  73. * Returns a temporary FileSystem object. A temporary filesystem may be deleted
  74. * by the user agent at its discretion.
  75. *
  76. * @param {number} size The size requested for the filesystem, in bytes.
  77. * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
  78. * error occurs, the errback is called with a {@link goog.fs.Error}.
  79. */
  80. goog.fs.getTemporary = function(size) {
  81. return goog.fs.get_(goog.fs.FileSystemType_.TEMPORARY, size);
  82. };
  83. /**
  84. * Returns a persistent FileSystem object. A persistent filesystem will never be
  85. * deleted without the user's or application's authorization.
  86. *
  87. * @param {number} size The size requested for the filesystem, in bytes.
  88. * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
  89. * error occurs, the errback is called with a {@link goog.fs.Error}.
  90. */
  91. goog.fs.getPersistent = function(size) {
  92. return goog.fs.get_(goog.fs.FileSystemType_.PERSISTENT, size);
  93. };
  94. /**
  95. * Creates a blob URL for a blob object.
  96. * Throws an error if the browser does not support Object Urls.
  97. *
  98. * TODO(user): Update references to this method to use
  99. * goog.fs.url.createObjectUrl instead.
  100. *
  101. * @param {!Blob} blob The object for which to create the URL.
  102. * @return {string} The URL for the object.
  103. */
  104. goog.fs.createObjectUrl = function(blob) {
  105. return goog.fs.url.createObjectUrl(blob);
  106. };
  107. /**
  108. * Revokes a URL created by {@link goog.fs.createObjectUrl}.
  109. * Throws an error if the browser does not support Object Urls.
  110. *
  111. * TODO(user): Update references to this method to use
  112. * goog.fs.url.revokeObjectUrl instead.
  113. *
  114. * @param {string} url The URL to revoke.
  115. */
  116. goog.fs.revokeObjectUrl = function(url) {
  117. goog.fs.url.revokeObjectUrl(url);
  118. };
  119. /**
  120. * Checks whether this browser supports Object Urls. If not, calls to
  121. * createObjectUrl and revokeObjectUrl will result in an error.
  122. *
  123. * TODO(user): Update references to this method to use
  124. * goog.fs.url.browserSupportsObjectUrls instead.
  125. *
  126. * @return {boolean} True if this browser supports Object Urls.
  127. */
  128. goog.fs.browserSupportsObjectUrls = function() {
  129. return goog.fs.url.browserSupportsObjectUrls();
  130. };
  131. /**
  132. * Concatenates one or more values together and converts them to a Blob.
  133. *
  134. * @param {...(string|!Blob|!ArrayBuffer)} var_args The values that will make up
  135. * the resulting blob.
  136. * @return {!Blob} The blob.
  137. */
  138. goog.fs.getBlob = function(var_args) {
  139. var BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;
  140. if (goog.isDef(BlobBuilder)) {
  141. var bb = new BlobBuilder();
  142. for (var i = 0; i < arguments.length; i++) {
  143. bb.append(arguments[i]);
  144. }
  145. return bb.getBlob();
  146. } else {
  147. return goog.fs.getBlobWithProperties(goog.array.toArray(arguments));
  148. }
  149. };
  150. /**
  151. * Creates a blob with the given properties.
  152. * See https://developer.mozilla.org/en-US/docs/Web/API/Blob for more details.
  153. *
  154. * @param {Array<string|!Blob>} parts The values that will make up the
  155. * resulting blob.
  156. * @param {string=} opt_type The MIME type of the Blob.
  157. * @param {string=} opt_endings Specifies how strings containing newlines are to
  158. * be written out.
  159. * @return {!Blob} The blob.
  160. */
  161. goog.fs.getBlobWithProperties = function(parts, opt_type, opt_endings) {
  162. var BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;
  163. if (goog.isDef(BlobBuilder)) {
  164. var bb = new BlobBuilder();
  165. for (var i = 0; i < parts.length; i++) {
  166. bb.append(parts[i], opt_endings);
  167. }
  168. return bb.getBlob(opt_type);
  169. } else if (goog.isDef(goog.global.Blob)) {
  170. var properties = {};
  171. if (opt_type) {
  172. properties['type'] = opt_type;
  173. }
  174. if (opt_endings) {
  175. properties['endings'] = opt_endings;
  176. }
  177. return new Blob(parts, properties);
  178. } else {
  179. throw Error('This browser doesn\'t seem to support creating Blobs');
  180. }
  181. };
  182. /**
  183. * Converts a Blob or a File into a string. This should only be used when the
  184. * blob is known to be small.
  185. *
  186. * @param {!Blob} blob The blob to convert.
  187. * @param {string=} opt_encoding The name of the encoding to use.
  188. * @return {!goog.async.Deferred} The deferred string. If an error occurrs, the
  189. * errback is called with a {@link goog.fs.Error}.
  190. * @deprecated Use {@link goog.fs.FileReader.readAsText} instead.
  191. */
  192. goog.fs.blobToString = function(blob, opt_encoding) {
  193. return goog.fs.FileReader.readAsText(blob, opt_encoding);
  194. };
  195. /**
  196. * Slices the blob. The returned blob contains data from the start byte
  197. * (inclusive) till the end byte (exclusive). Negative indices can be used
  198. * to count bytes from the end of the blob (-1 == blob.size - 1). Indices
  199. * are always clamped to blob range. If end is omitted, all the data till
  200. * the end of the blob is taken.
  201. *
  202. * @param {!Blob} blob The blob to be sliced.
  203. * @param {number} start Index of the starting byte.
  204. * @param {number=} opt_end Index of the ending byte.
  205. * @return {Blob} The blob slice or null if not supported.
  206. */
  207. goog.fs.sliceBlob = function(blob, start, opt_end) {
  208. if (!goog.isDef(opt_end)) {
  209. opt_end = blob.size;
  210. }
  211. if (blob.webkitSlice) {
  212. // Natively accepts negative indices, clamping to the blob range and
  213. // range end is optional. See http://trac.webkit.org/changeset/83873
  214. return blob.webkitSlice(start, opt_end);
  215. } else if (blob.mozSlice) {
  216. // Natively accepts negative indices, clamping to the blob range and
  217. // range end is optional. See https://developer.mozilla.org/en/DOM/Blob
  218. // and http://hg.mozilla.org/mozilla-central/rev/dae833f4d934
  219. return blob.mozSlice(start, opt_end);
  220. } else if (blob.slice) {
  221. // Old versions of Firefox and Chrome use the original specification.
  222. // Negative indices are not accepted, only range end is clamped and
  223. // range end specification is obligatory.
  224. // See http://www.w3.org/TR/2009/WD-FileAPI-20091117/
  225. if ((goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('13.0')) ||
  226. (goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('537.1'))) {
  227. if (start < 0) {
  228. start += blob.size;
  229. }
  230. if (start < 0) {
  231. start = 0;
  232. }
  233. if (opt_end < 0) {
  234. opt_end += blob.size;
  235. }
  236. if (opt_end < start) {
  237. opt_end = start;
  238. }
  239. return blob.slice(start, opt_end - start);
  240. }
  241. // IE and the latest versions of Firefox and Chrome use the new
  242. // specification. Natively accepts negative indices, clamping to the blob
  243. // range and range end is optional.
  244. // See http://dev.w3.org/2006/webapi/FileAPI/
  245. return blob.slice(start, opt_end);
  246. }
  247. return null;
  248. };