| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| var exec = require('cordova/exec'), |
| FileError = require('./FileError'), |
| ProgressEvent = require('./ProgressEvent'); |
| |
| /** |
| * This class writes to the mobile device file system. |
| * |
| * For Android: |
| * The root directory is the root of the file system. |
| * To write to the SD card, the file name is "sdcard/my_file.txt" |
| * |
| * @constructor |
| * @param file {File} File object containing file properties |
| * @param append if true write to the end of the file, otherwise overwrite the file |
| */ |
| var FileWriter = function(file) { |
| this.fileName = ""; |
| this.length = 0; |
| if (file) { |
| this.fileName = file.fullPath || file; |
| this.length = file.size || 0; |
| } |
| // default is to write at the beginning of the file |
| this.position = 0; |
| |
| this.readyState = 0; // EMPTY |
| |
| this.result = null; |
| |
| // Error |
| this.error = null; |
| |
| // Event handlers |
| this.onwritestart = null; // When writing starts |
| this.onprogress = null; // While writing the file, and reporting partial file data |
| this.onwrite = null; // When the write has successfully completed. |
| this.onwriteend = null; // When the request has completed (either in success or failure). |
| this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method. |
| this.onerror = null; // When the write has failed (see errors). |
| }; |
| |
| // States |
| FileWriter.INIT = 0; |
| FileWriter.WRITING = 1; |
| FileWriter.DONE = 2; |
| |
| /** |
| * Abort writing file. |
| */ |
| FileWriter.prototype.abort = function() { |
| // check for invalid state |
| if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) { |
| throw new FileError(FileError.INVALID_STATE_ERR); |
| } |
| |
| // set error |
| this.error = new FileError(FileError.ABORT_ERR); |
| |
| this.readyState = FileWriter.DONE; |
| |
| // If abort callback |
| if (typeof this.onabort === "function") { |
| this.onabort(new ProgressEvent("abort", {"target":this})); |
| } |
| |
| // If write end callback |
| if (typeof this.onwriteend === "function") { |
| this.onwriteend(new ProgressEvent("writeend", {"target":this})); |
| } |
| }; |
| |
| /** |
| * Writes data to the file |
| * |
| * @param data text or blob to be written |
| */ |
| FileWriter.prototype.write = function(data) { |
| |
| var that=this; |
| var supportsBinary = (typeof window.Blob !== 'undefined' && typeof window.ArrayBuffer !== 'undefined'); |
| var isBinary; |
| |
| // Check to see if the incoming data is a blob |
| if (data instanceof File || (supportsBinary && data instanceof Blob)) { |
| var fileReader = new FileReader(); |
| fileReader.onload = function() { |
| // Call this method again, with the arraybuffer as argument |
| FileWriter.prototype.write.call(that, this.result); |
| }; |
| if (supportsBinary) { |
| fileReader.readAsArrayBuffer(data); |
| } else { |
| fileReader.readAsText(data); |
| } |
| return; |
| } |
| |
| // Mark data type for safer transport over the binary bridge |
| isBinary = supportsBinary && (data instanceof ArrayBuffer); |
| |
| // Throw an exception if we are already writing a file |
| if (this.readyState === FileWriter.WRITING) { |
| throw new FileError(FileError.INVALID_STATE_ERR); |
| } |
| |
| // WRITING state |
| this.readyState = FileWriter.WRITING; |
| |
| var me = this; |
| |
| // If onwritestart callback |
| if (typeof me.onwritestart === "function") { |
| me.onwritestart(new ProgressEvent("writestart", {"target":me})); |
| } |
| |
| // Write file |
| exec( |
| // Success callback |
| function(r) { |
| // If DONE (cancelled), then don't do anything |
| if (me.readyState === FileWriter.DONE) { |
| return; |
| } |
| |
| // position always increases by bytes written because file would be extended |
| me.position += r; |
| // The length of the file is now where we are done writing. |
| |
| me.length = me.position; |
| |
| // DONE state |
| me.readyState = FileWriter.DONE; |
| |
| // If onwrite callback |
| if (typeof me.onwrite === "function") { |
| me.onwrite(new ProgressEvent("write", {"target":me})); |
| } |
| |
| // If onwriteend callback |
| if (typeof me.onwriteend === "function") { |
| me.onwriteend(new ProgressEvent("writeend", {"target":me})); |
| } |
| }, |
| // Error callback |
| function(e) { |
| // If DONE (cancelled), then don't do anything |
| if (me.readyState === FileWriter.DONE) { |
| return; |
| } |
| |
| // DONE state |
| me.readyState = FileWriter.DONE; |
| |
| // Save error |
| me.error = new FileError(e); |
| |
| // If onerror callback |
| if (typeof me.onerror === "function") { |
| me.onerror(new ProgressEvent("error", {"target":me})); |
| } |
| |
| // If onwriteend callback |
| if (typeof me.onwriteend === "function") { |
| me.onwriteend(new ProgressEvent("writeend", {"target":me})); |
| } |
| }, "File", "write", [this.fileName, data, this.position, isBinary]); |
| }; |
| |
| /** |
| * Moves the file pointer to the location specified. |
| * |
| * If the offset is a negative number the position of the file |
| * pointer is rewound. If the offset is greater than the file |
| * size the position is set to the end of the file. |
| * |
| * @param offset is the location to move the file pointer to. |
| */ |
| FileWriter.prototype.seek = function(offset) { |
| // Throw an exception if we are already writing a file |
| if (this.readyState === FileWriter.WRITING) { |
| throw new FileError(FileError.INVALID_STATE_ERR); |
| } |
| |
| if (!offset && offset !== 0) { |
| return; |
| } |
| |
| // See back from end of file. |
| if (offset < 0) { |
| this.position = Math.max(offset + this.length, 0); |
| } |
| // Offset is bigger than file size so set position |
| // to the end of the file. |
| else if (offset > this.length) { |
| this.position = this.length; |
| } |
| // Offset is between 0 and file size so set the position |
| // to start writing. |
| else { |
| this.position = offset; |
| } |
| }; |
| |
| /** |
| * Truncates the file to the size specified. |
| * |
| * @param size to chop the file at. |
| */ |
| FileWriter.prototype.truncate = function(size) { |
| // Throw an exception if we are already writing a file |
| if (this.readyState === FileWriter.WRITING) { |
| throw new FileError(FileError.INVALID_STATE_ERR); |
| } |
| |
| // WRITING state |
| this.readyState = FileWriter.WRITING; |
| |
| var me = this; |
| |
| // If onwritestart callback |
| if (typeof me.onwritestart === "function") { |
| me.onwritestart(new ProgressEvent("writestart", {"target":this})); |
| } |
| |
| // Write file |
| exec( |
| // Success callback |
| function(r) { |
| // If DONE (cancelled), then don't do anything |
| if (me.readyState === FileWriter.DONE) { |
| return; |
| } |
| |
| // DONE state |
| me.readyState = FileWriter.DONE; |
| |
| // Update the length of the file |
| me.length = r; |
| me.position = Math.min(me.position, r); |
| |
| // If onwrite callback |
| if (typeof me.onwrite === "function") { |
| me.onwrite(new ProgressEvent("write", {"target":me})); |
| } |
| |
| // If onwriteend callback |
| if (typeof me.onwriteend === "function") { |
| me.onwriteend(new ProgressEvent("writeend", {"target":me})); |
| } |
| }, |
| // Error callback |
| function(e) { |
| // If DONE (cancelled), then don't do anything |
| if (me.readyState === FileWriter.DONE) { |
| return; |
| } |
| |
| // DONE state |
| me.readyState = FileWriter.DONE; |
| |
| // Save error |
| me.error = new FileError(e); |
| |
| // If onerror callback |
| if (typeof me.onerror === "function") { |
| me.onerror(new ProgressEvent("error", {"target":me})); |
| } |
| |
| // If onwriteend callback |
| if (typeof me.onwriteend === "function") { |
| me.onwriteend(new ProgressEvent("writeend", {"target":me})); |
| } |
| }, "File", "truncate", [this.fileName, size]); |
| }; |
| |
| module.exports = FileWriter; |