openEventsPlatformApp/plugins/cordova-plugin-file/www/FileWriter.js
plugins/cordova-plugin-file/www/FileWriter.jsRaw
1/*
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20*/
21
22var exec = require('cordova/exec'),
23 FileError = require('./FileError'),
24 ProgressEvent = require('./ProgressEvent');
25
26/**
27 * This class writes to the mobile device file system.
28 *
29 * For Android:
30 * The root directory is the root of the file system.
31 * To write to the SD card, the file name is "sdcard/my_file.txt"
32 *
33 * @constructor
34 * @param file {File} File object containing file properties
35 * @param append if true write to the end of the file, otherwise overwrite the file
36 */
37var FileWriter = function(file) {
38 this.fileName = "";
39 this.length = 0;
40 if (file) {
41 this.localURL = file.localURL || file;
42 this.length = file.size || 0;
43 }
44 // default is to write at the beginning of the file
45 this.position = 0;
46
47 this.readyState = 0; // EMPTY
48
49 this.result = null;
50
51 // Error
52 this.error = null;
53
54 // Event handlers
55 this.onwritestart = null; // When writing starts
56 this.onprogress = null; // While writing the file, and reporting partial file data
57 this.onwrite = null; // When the write has successfully completed.
58 this.onwriteend = null; // When the request has completed (either in success or failure).
59 this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method.
60 this.onerror = null; // When the write has failed (see errors).
61};
62
63// States
64FileWriter.INIT = 0;
65FileWriter.WRITING = 1;
66FileWriter.DONE = 2;
67
68/**
69 * Abort writing file.
70 */
71FileWriter.prototype.abort = function() {
72 // check for invalid state
73 if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
74 throw new FileError(FileError.INVALID_STATE_ERR);
75 }
76
77 // set error
78 this.error = new FileError(FileError.ABORT_ERR);
79
80 this.readyState = FileWriter.DONE;
81
82 // If abort callback
83 if (typeof this.onabort === "function") {
84 this.onabort(new ProgressEvent("abort", {"target":this}));
85 }
86
87 // If write end callback
88 if (typeof this.onwriteend === "function") {
89 this.onwriteend(new ProgressEvent("writeend", {"target":this}));
90 }
91};
92
93/**
94 * Writes data to the file
95 *
96 * @param data text or blob to be written
97 * @param isPendingBlobReadResult {Boolean} true if the data is the pending blob read operation result
98 */
99FileWriter.prototype.write = function(data, isPendingBlobReadResult) {
100
101 var that=this;
102 var supportsBinary = (typeof window.Blob !== 'undefined' && typeof window.ArrayBuffer !== 'undefined');
103 var isProxySupportBlobNatively = (cordova.platformId === "windows8" || cordova.platformId === "windows");
104 var isBinary;
105
106 // Check to see if the incoming data is a blob
107 if (data instanceof File || (!isProxySupportBlobNatively && supportsBinary && data instanceof Blob)) {
108 var fileReader = new FileReader();
109 fileReader.onload = function() {
110 // Call this method again, with the arraybuffer as argument
111 FileWriter.prototype.write.call(that, this.result, true /* isPendingBlobReadResult */);
112 };
113 fileReader.onerror = function () {
114 // DONE state
115 that.readyState = FileWriter.DONE;
116
117 // Save error
118 that.error = this.error;
119
120 // If onerror callback
121 if (typeof that.onerror === "function") {
122 that.onerror(new ProgressEvent("error", {"target":that}));
123 }
124
125 // If onwriteend callback
126 if (typeof that.onwriteend === "function") {
127 that.onwriteend(new ProgressEvent("writeend", {"target":that}));
128 }
129 };
130
131 // WRITING state
132 this.readyState = FileWriter.WRITING;
133
134 if (supportsBinary) {
135 fileReader.readAsArrayBuffer(data);
136 } else {
137 fileReader.readAsText(data);
138 }
139 return;
140 }
141
142 // Mark data type for safer transport over the binary bridge
143 isBinary = supportsBinary && (data instanceof ArrayBuffer);
144 if (isBinary && cordova.platformId === "windowsphone") {
145 // create a plain array, using the keys from the Uint8Array view so that we can serialize it
146 data = Array.apply(null, new Uint8Array(data));
147 }
148
149 // Throw an exception if we are already writing a file
150 if (this.readyState === FileWriter.WRITING && !isPendingBlobReadResult) {
151 throw new FileError(FileError.INVALID_STATE_ERR);
152 }
153
154 // WRITING state
155 this.readyState = FileWriter.WRITING;
156
157 var me = this;
158
159 // If onwritestart callback
160 if (typeof me.onwritestart === "function") {
161 me.onwritestart(new ProgressEvent("writestart", {"target":me}));
162 }
163
164 // Write file
165 exec(
166 // Success callback
167 function(r) {
168 // If DONE (cancelled), then don't do anything
169 if (me.readyState === FileWriter.DONE) {
170 return;
171 }
172
173 // position always increases by bytes written because file would be extended
174 me.position += r;
175 // The length of the file is now where we are done writing.
176
177 me.length = me.position;
178
179 // DONE state
180 me.readyState = FileWriter.DONE;
181
182 // If onwrite callback
183 if (typeof me.onwrite === "function") {
184 me.onwrite(new ProgressEvent("write", {"target":me}));
185 }
186
187 // If onwriteend callback
188 if (typeof me.onwriteend === "function") {
189 me.onwriteend(new ProgressEvent("writeend", {"target":me}));
190 }
191 },
192 // Error callback
193 function(e) {
194 // If DONE (cancelled), then don't do anything
195 if (me.readyState === FileWriter.DONE) {
196 return;
197 }
198
199 // DONE state
200 me.readyState = FileWriter.DONE;
201
202 // Save error
203 me.error = new FileError(e);
204
205 // If onerror callback
206 if (typeof me.onerror === "function") {
207 me.onerror(new ProgressEvent("error", {"target":me}));
208 }
209
210 // If onwriteend callback
211 if (typeof me.onwriteend === "function") {
212 me.onwriteend(new ProgressEvent("writeend", {"target":me}));
213 }
214 }, "File", "write", [this.localURL, data, this.position, isBinary]);
215};
216
217/**
218 * Moves the file pointer to the location specified.
219 *
220 * If the offset is a negative number the position of the file
221 * pointer is rewound. If the offset is greater than the file
222 * size the position is set to the end of the file.
223 *
224 * @param offset is the location to move the file pointer to.
225 */
226FileWriter.prototype.seek = function(offset) {
227 // Throw an exception if we are already writing a file
228 if (this.readyState === FileWriter.WRITING) {
229 throw new FileError(FileError.INVALID_STATE_ERR);
230 }
231
232 if (!offset && offset !== 0) {
233 return;
234 }
235
236 // See back from end of file.
237 if (offset < 0) {
238 this.position = Math.max(offset + this.length, 0);
239 }
240 // Offset is bigger than file size so set position
241 // to the end of the file.
242 else if (offset > this.length) {
243 this.position = this.length;
244 }
245 // Offset is between 0 and file size so set the position
246 // to start writing.
247 else {
248 this.position = offset;
249 }
250};
251
252/**
253 * Truncates the file to the size specified.
254 *
255 * @param size to chop the file at.
256 */
257FileWriter.prototype.truncate = function(size) {
258 // Throw an exception if we are already writing a file
259 if (this.readyState === FileWriter.WRITING) {
260 throw new FileError(FileError.INVALID_STATE_ERR);
261 }
262
263 // WRITING state
264 this.readyState = FileWriter.WRITING;
265
266 var me = this;
267
268 // If onwritestart callback
269 if (typeof me.onwritestart === "function") {
270 me.onwritestart(new ProgressEvent("writestart", {"target":this}));
271 }
272
273 // Write file
274 exec(
275 // Success callback
276 function(r) {
277 // If DONE (cancelled), then don't do anything
278 if (me.readyState === FileWriter.DONE) {
279 return;
280 }
281
282 // DONE state
283 me.readyState = FileWriter.DONE;
284
285 // Update the length of the file
286 me.length = r;
287 me.position = Math.min(me.position, r);
288
289 // If onwrite callback
290 if (typeof me.onwrite === "function") {
291 me.onwrite(new ProgressEvent("write", {"target":me}));
292 }
293
294 // If onwriteend callback
295 if (typeof me.onwriteend === "function") {
296 me.onwriteend(new ProgressEvent("writeend", {"target":me}));
297 }
298 },
299 // Error callback
300 function(e) {
301 // If DONE (cancelled), then don't do anything
302 if (me.readyState === FileWriter.DONE) {
303 return;
304 }
305
306 // DONE state
307 me.readyState = FileWriter.DONE;
308
309 // Save error
310 me.error = new FileError(e);
311
312 // If onerror callback
313 if (typeof me.onerror === "function") {
314 me.onerror(new ProgressEvent("error", {"target":me}));
315 }
316
317 // If onwriteend callback
318 if (typeof me.onwriteend === "function") {
319 me.onwriteend(new ProgressEvent("writeend", {"target":me}));
320 }
321 }, "File", "truncate", [this.localURL, size]);
322};
323
324module.exports = FileWriter;