123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- /*
- *
- * 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');
- var FileError = require('./FileError');
- var FileReader = require('./FileReader');
- var 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.localURL = file.localURL || 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
- * @param isPendingBlobReadResult {Boolean} true if the data is the pending blob read operation result
- */
- FileWriter.prototype.write = function (data, isPendingBlobReadResult) {
-
- var that = this;
- var supportsBinary = (typeof window.Blob !== 'undefined' && typeof window.ArrayBuffer !== 'undefined');
- /* eslint-disable no-undef */
- var isProxySupportBlobNatively = (cordova.platformId === 'windows8' || cordova.platformId === 'windows');
- var isBinary;
-
- // Check to see if the incoming data is a blob
- if (data instanceof File || (!isProxySupportBlobNatively && supportsBinary && data instanceof Blob)) {
- var fileReader = new FileReader();
- /* eslint-enable no-undef */
- fileReader.onload = function () {
- // Call this method again, with the arraybuffer as argument
- FileWriter.prototype.write.call(that, this.result, true /* isPendingBlobReadResult */);
- };
- fileReader.onerror = function () {
- // DONE state
- that.readyState = FileWriter.DONE;
-
- // Save error
- that.error = this.error;
-
- // If onerror callback
- if (typeof that.onerror === 'function') {
- that.onerror(new ProgressEvent('error', {'target': that}));
- }
-
- // If onwriteend callback
- if (typeof that.onwriteend === 'function') {
- that.onwriteend(new ProgressEvent('writeend', {'target': that}));
- }
- };
-
- // WRITING state
- this.readyState = FileWriter.WRITING;
-
- 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);
- if (isBinary && cordova.platformId === 'windowsphone') { // eslint-disable-line no-undef
- // create a plain array, using the keys from the Uint8Array view so that we can serialize it
- data = Array.apply(null, new Uint8Array(data));
- }
-
- // Throw an exception if we are already writing a file
- if (this.readyState === FileWriter.WRITING && !isPendingBlobReadResult) {
- 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.localURL, 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.localURL, size]);
- };
-
- module.exports = FileWriter;
|