openEventsPlatformApp/plugins/cordova-plugin-file/src/windows/FileProxy.js
plugins/cordova-plugin-file/src/windows/FileProxy.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
22/* global Windows, WinJS, MSApp */
23
24var File = require('./File'),
25 FileError = require('./FileError'),
26 Flags = require('./Flags'),
27 FileSystem = require('./FileSystem'),
28 LocalFileSystem = require('./LocalFileSystem'),
29 utils = require('cordova/utils');
30
31function Entry(isFile, isDirectory, name, fullPath, filesystemName, nativeURL) {
32 this.isFile = !!isFile;
33 this.isDirectory = !!isDirectory;
34 this.name = name || '';
35 this.fullPath = fullPath || '';
36 this.filesystemName = filesystemName || null;
37 this.nativeURL = nativeURL || null;
38}
39
40var FileEntry = function(name, fullPath, filesystemName, nativeURL) {
41 FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath, filesystemName, nativeURL]);
42};
43
44utils.extend(FileEntry, Entry);
45
46var DirectoryEntry = function(name, fullPath, filesystemName, nativeURL) {
47 DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath, filesystemName, nativeURL);
48};
49
50utils.extend(DirectoryEntry, Entry);
51
52
53var getFolderFromPathAsync = Windows.Storage.StorageFolder.getFolderFromPathAsync;
54var getFileFromPathAsync = Windows.Storage.StorageFile.getFileFromPathAsync;
55
56function writeBytesAsync(storageFile, data, position) {
57 return storageFile.openAsync(Windows.Storage.FileAccessMode.readWrite)
58 .then(function (output) {
59 output.seek(position);
60 var dataWriter = new Windows.Storage.Streams.DataWriter(output);
61 dataWriter.writeBytes(data);
62 return dataWriter.storeAsync().then(function (size) {
63 output.size = position+size;
64 return dataWriter.flushAsync().then(function() {
65 output.close();
66 return size;
67 });
68 });
69 });
70}
71
72function writeTextAsync(storageFile, data, position) {
73 return storageFile.openAsync(Windows.Storage.FileAccessMode.readWrite)
74 .then(function (output) {
75 output.seek(position);
76 var dataWriter = new Windows.Storage.Streams.DataWriter(output);
77 dataWriter.writeString(data);
78 return dataWriter.storeAsync().then(function (size) {
79 output.size = position+size;
80 return dataWriter.flushAsync().then(function() {
81 output.close();
82 return size;
83 });
84 });
85 });
86}
87
88function writeBlobAsync(storageFile, data, position) {
89 return storageFile.openAsync(Windows.Storage.FileAccessMode.readWrite)
90 .then(function (output) {
91 output.seek(position);
92 var dataSize = data.size;
93 var input = (data.detachStream || data.msDetachStream).call(data);
94
95 // Copy the stream from the blob to the File stream
96 return Windows.Storage.Streams.RandomAccessStream.copyAsync(input, output)
97 .then(function () {
98 output.size = position+dataSize;
99 return output.flushAsync().then(function () {
100 input.close();
101 output.close();
102
103 return dataSize;
104 });
105 });
106 });
107}
108
109function writeArrayBufferAsync(storageFile, data, position) {
110 return writeBlobAsync(storageFile, new Blob([data]), position);
111}
112
113function cordovaPathToNative(path) {
114 // turn / into \\
115 var cleanPath = path.replace(/\//g, '\\');
116 // turn \\ into \
117 cleanPath = cleanPath.replace(/\\+/g, '\\');
118 return cleanPath;
119}
120
121function nativePathToCordova(path) {
122 var cleanPath = path.replace(/\\/g, '/');
123 return cleanPath;
124}
125
126var driveRE = new RegExp("^[/]*([A-Z]:)");
127var invalidNameRE = /[\\?*|"<>:]/;
128function validName(name) {
129 return !invalidNameRE.test(name.replace(driveRE,''));
130}
131
132function sanitize(path) {
133 var slashesRE = new RegExp('/{2,}','g');
134 var components = path.replace(slashesRE, '/').split(/\/+/);
135 // Remove double dots, use old school array iteration instead of RegExp
136 // since it is impossible to debug them
137 for (var index = 0; index < components.length; ++index) {
138 if (components[index] === "..") {
139 components.splice(index, 1);
140 if (index > 0) {
141 // if we're not in the start of array then remove preceeding path component,
142 // In case if relative path points above the root directory, just ignore double dots
143 // See file.spec.111 should not traverse above above the root directory for test case
144 components.splice(index-1, 1);
145 --index;
146 }
147 }
148 }
149 return components.join('/');
150}
151
152var WinFS = function(name, root) {
153 this.winpath = root.winpath;
154 if (this.winpath && !/\/$/.test(this.winpath)) {
155 this.winpath += "/";
156 }
157 this.makeNativeURL = function (path) {
158 //CB-11848: This RE supposed to match all leading slashes in sanitized path.
159 //Removing leading slash to avoid duplicating because this.root.nativeURL already has trailing slash
160 var regLeadingSlashes = /^\/*/;
161 var sanitizedPath = sanitize(path.replace(':', '%3A')).replace(regLeadingSlashes, '');
162 return FileSystem.encodeURIPath(this.root.nativeURL + sanitizedPath);
163 };
164 root.fullPath = '/';
165 if (!root.nativeURL)
166 root.nativeURL = 'file://'+sanitize(this.winpath + root.fullPath).replace(':','%3A');
167 WinFS.__super__.constructor.call(this, name, root);
168};
169
170utils.extend(WinFS, FileSystem);
171
172WinFS.prototype.__format__ = function(fullPath) {
173 var path = sanitize('/'+this.name+(fullPath[0]==='/'?'':'/')+FileSystem.encodeURIPath(fullPath));
174 return 'cdvfile://localhost' + path;
175};
176
177var windowsPaths = {
178 dataDirectory: "ms-appdata:///local/",
179 cacheDirectory: "ms-appdata:///temp/",
180 tempDirectory: "ms-appdata:///temp/",
181 syncedDataDirectory: "ms-appdata:///roaming/",
182 applicationDirectory: "ms-appx:///",
183 applicationStorageDirectory: "ms-appx:///"
184};
185
186var AllFileSystems;
187
188function getAllFS() {
189 if (!AllFileSystems) {
190 AllFileSystems = {
191 'persistent':
192 Object.freeze(new WinFS('persistent', {
193 name: 'persistent',
194 nativeURL: 'ms-appdata:///local',
195 winpath: nativePathToCordova(Windows.Storage.ApplicationData.current.localFolder.path)
196 })),
197 'temporary':
198 Object.freeze(new WinFS('temporary', {
199 name: 'temporary',
200 nativeURL: 'ms-appdata:///temp',
201 winpath: nativePathToCordova(Windows.Storage.ApplicationData.current.temporaryFolder.path)
202 })),
203 'application':
204 Object.freeze(new WinFS('application', {
205 name: 'application',
206 nativeURL: 'ms-appx:///',
207 winpath: nativePathToCordova(Windows.ApplicationModel.Package.current.installedLocation.path)
208 })),
209 'root':
210 Object.freeze(new WinFS('root', {
211 name: 'root',
212 //nativeURL: 'file:///'
213 winpath: ''
214 }))
215 };
216 }
217 return AllFileSystems;
218}
219
220function getFS(name) {
221 return getAllFS()[name];
222}
223
224FileSystem.prototype.__format__ = function(fullPath) {
225 return getFS(this.name).__format__(fullPath);
226};
227
228require('./fileSystems').getFs = function(name, callback) {
229 setTimeout(function(){callback(getFS(name));});
230};
231
232function getFilesystemFromPath(path) {
233 var res;
234 var allfs = getAllFS();
235 Object.keys(allfs).some(function(fsn) {
236 var fs = allfs[fsn];
237 if (path.indexOf(fs.winpath) === 0)
238 res = fs;
239 return res;
240 });
241 return res;
242}
243
244var msapplhRE = new RegExp('^ms-appdata://localhost/');
245function pathFromURL(url) {
246 url=url.replace(msapplhRE,'ms-appdata:///');
247 var path = decodeURIComponent(url);
248 // support for file name with parameters
249 if (/\?/g.test(path)) {
250 path = String(path).split("?")[0];
251 }
252 if (path.indexOf("file:/")===0) {
253 if (path.indexOf("file://") !== 0) {
254 url = "file:///" + url.substr(6);
255 }
256 }
257
258 ['file://','ms-appdata:///','ms-appx://','cdvfile://localhost/'].every(function(p) {
259 if (path.indexOf(p)!==0)
260 return true;
261 var thirdSlash = path.indexOf("/", p.length);
262 if (thirdSlash < 0) {
263 path = "";
264 } else {
265 path = sanitize(path.substr(thirdSlash));
266 }
267 });
268
269 return path.replace(driveRE,'$1');
270}
271
272function getFilesystemFromURL(url) {
273 url=url.replace(msapplhRE,'ms-appdata:///');
274 var res;
275 if (url.indexOf("file:/")===0)
276 res = getFilesystemFromPath(pathFromURL(url));
277 else {
278 var allfs = getAllFS();
279 Object.keys(allfs).every(function(fsn) {
280 var fs = allfs[fsn];
281 if (url.indexOf(fs.root.nativeURL) === 0 ||
282 url.indexOf('cdvfile://localhost/'+fs.name+'/') === 0)
283 {
284 res = fs;
285 return false;
286 }
287 return true;
288 });
289 }
290 return res;
291}
292
293function getFsPathForWinPath(fs, wpath) {
294 var path = nativePathToCordova(wpath);
295 if (path.indexOf(fs.winpath) !== 0)
296 return null;
297 return path.replace(fs.winpath,'/');
298}
299
300var WinError = {
301 invalidArgument: -2147024809,
302 fileNotFound: -2147024894,
303 accessDenied: -2147024891
304};
305
306function openPath(path, ops) {
307 ops=ops?ops:{};
308 return new WinJS.Promise(function (complete,failed) {
309 getFileFromPathAsync(path).done(
310 function(file) {
311 complete({file:file});
312 },
313 function(err) {
314 if (err.number != WinError.fileNotFound && err.number != WinError.invalidArgument)
315 failed(FileError.NOT_READABLE_ERR);
316 getFolderFromPathAsync(path)
317 .done(
318 function(dir) {
319 if (!ops.getContent)
320 complete({folder:dir});
321 else
322 WinJS.Promise.join({
323 files:dir.getFilesAsync(),
324 folders:dir.getFoldersAsync()
325 }).done(
326 function(a) {
327 complete({
328 folder:dir,
329 files:a.files,
330 folders:a.folders
331 });
332 },
333 function(err) {
334 failed(FileError.NOT_READABLE_ERR);
335 }
336 );
337 },
338 function(err) {
339 if (err.number == WinError.fileNotFound || err.number == WinError.invalidArgument)
340 complete({});
341 else
342 failed(FileError.NOT_READABLE_ERR);
343 }
344 );
345 }
346 );
347 });
348}
349
350function copyFolder(src,dst,name) {
351 name = name?name:src.name;
352 return new WinJS.Promise(function (complete,failed) {
353 WinJS.Promise.join({
354 fld:dst.createFolderAsync(name, Windows.Storage.CreationCollisionOption.openIfExists),
355 files:src.getFilesAsync(),
356 folders:src.getFoldersAsync()
357 }).done(
358 function(the) {
359 if (!(the.files.length || the.folders.length)) {
360 complete();
361 return;
362 }
363 var todo = the.files.length;
364 var copyfolders = function() {
365 if (!(todo--)) {
366 complete();
367 return;
368 }
369 copyFolder(the.folders[todo],dst)
370 .done(function() { copyfolders(); }, failed);
371 };
372 var copyfiles = function() {
373 if (!(todo--)) {
374 todo = the.folders.length;
375 copyfolders();
376 return;
377 }
378 the.files[todo].copyAsync(the.fld)
379 .done(function() { copyfiles(); }, failed);
380 };
381 copyfiles();
382 },
383 failed
384 );
385 });
386}
387
388function moveFolder(src,dst,name) {
389 name = name?name:src.name;
390 return new WinJS.Promise(function (complete,failed) {
391 WinJS.Promise.join({
392 fld: dst.createFolderAsync(name, Windows.Storage.CreationCollisionOption.openIfExists),
393 files: src.getFilesAsync(),
394 folders: src.getFoldersAsync()
395 }).done(
396 function(the) {
397 if (!(the.files.length || the.folders.length)) {
398 complete();
399 return;
400 }
401 var todo = the.files.length;
402 var movefolders = function() {
403 if (!(todo--)) {
404 src.deleteAsync().done(complete,failed);
405 return;
406 }
407 moveFolder(the.folders[todo], the.fld)
408 .done(movefolders,failed);
409 };
410 var movefiles = function() {
411 if (!(todo--)) {
412 todo = the.folders.length;
413 movefolders();
414 return;
415 }
416 the.files[todo].moveAsync(the.fld)
417 .done(function() { movefiles(); }, failed);
418 };
419 movefiles();
420 },
421 failed
422 );
423 });
424}
425
426function transport(success, fail, args, ops) { // ["fullPath","parent", "newName"]
427 var src = args[0];
428 var parent = args[1];
429 var name = args[2];
430
431 var srcFS = getFilesystemFromURL(src);
432 var dstFS = getFilesystemFromURL(parent);
433 var srcPath = pathFromURL(src);
434 var dstPath = pathFromURL(parent);
435 if (!(srcFS && dstFS && validName(name))){
436 fail(FileError.ENCODING_ERR);
437 return;
438 }
439
440 var srcWinPath = cordovaPathToNative(sanitize(srcFS.winpath + srcPath));
441 var dstWinPath = cordovaPathToNative(sanitize(dstFS.winpath + dstPath));
442 var tgtFsPath = sanitize(dstPath+'/'+name);
443 var tgtWinPath = cordovaPathToNative(sanitize(dstFS.winpath + dstPath+'/'+name));
444 if (srcWinPath == dstWinPath || srcWinPath == tgtWinPath) {
445 fail(FileError.INVALID_MODIFICATION_ERR);
446 return;
447 }
448
449
450 WinJS.Promise.join({
451 src:openPath(srcWinPath),
452 dst:openPath(dstWinPath),
453 tgt:openPath(tgtWinPath,{getContent:true})
454 })
455 .done(
456 function (the) {
457 if ((!the.dst.folder) || !(the.src.folder || the.src.file)) {
458 fail(FileError.NOT_FOUND_ERR);
459 return;
460 }
461 if ((the.src.folder && the.tgt.file) ||
462 (the.src.file && the.tgt.folder) ||
463 (the.tgt.folder && (the.tgt.files.length || the.tgt.folders.length))) {
464 fail(FileError.INVALID_MODIFICATION_ERR);
465 return;
466 }
467 if (the.src.file)
468 ops.fileOp(the.src.file,the.dst.folder, name, Windows.Storage.NameCollisionOption.replaceExisting)
469 .done(
470 function (storageFile) {
471 success(new FileEntry(
472 name,
473 tgtFsPath,
474 dstFS.name,
475 dstFS.makeNativeURL(tgtFsPath)
476 ));
477 },
478 function (err) {
479 fail(FileError.INVALID_MODIFICATION_ERR);
480 }
481 );
482 else
483 ops.folderOp(the.src.folder, the.dst.folder, name).done(
484 function () {
485 success(new DirectoryEntry(
486 name,
487 tgtFsPath,
488 dstFS.name,
489 dstFS.makeNativeURL(tgtFsPath)
490 ));
491 },
492 function() {
493 fail(FileError.INVALID_MODIFICATION_ERR);
494 }
495 );
496 },
497 function(err) {
498 fail(FileError.INVALID_MODIFICATION_ERR);
499 }
500 );
501}
502
503module.exports = {
504 requestAllFileSystems: function() {
505 return getAllFS();
506 },
507 requestAllPaths: function(success){
508 success(windowsPaths);
509 },
510 getFileMetadata: function (success, fail, args) {
511 module.exports.getMetadata(success, fail, args);
512 },
513
514 getMetadata: function (success, fail, args) {
515 var fs = getFilesystemFromURL(args[0]);
516 var path = pathFromURL(args[0]);
517 if (!fs || !validName(path)){
518 fail(FileError.ENCODING_ERR);
519 return;
520 }
521 var fullPath = cordovaPathToNative(fs.winpath + path);
522
523 var getMetadataForFile = function (storageFile) {
524 storageFile.getBasicPropertiesAsync().then(
525 function (basicProperties) {
526 success(new File(storageFile.name, storageFile.path, storageFile.fileType, basicProperties.dateModified, basicProperties.size));
527 }, function () {
528 fail(FileError.NOT_READABLE_ERR);
529 }
530 );
531 };
532
533 var getMetadataForFolder = function (storageFolder) {
534 storageFolder.getBasicPropertiesAsync().then(
535 function (basicProperties) {
536 var metadata = {
537 size: basicProperties.size,
538 lastModifiedDate: basicProperties.dateModified
539 };
540 success(metadata);
541 },
542 function () {
543 fail(FileError.NOT_READABLE_ERR);
544 }
545 );
546 };
547
548 getFileFromPathAsync(fullPath).then(getMetadataForFile,
549 function () {
550 getFolderFromPathAsync(fullPath).then(getMetadataForFolder,
551 function () {
552 fail(FileError.NOT_FOUND_ERR);
553 }
554 );
555 }
556 );
557 },
558
559 getParent: function (win, fail, args) { // ["fullPath"]
560 var fs = getFilesystemFromURL(args[0]);
561 var path = pathFromURL(args[0]);
562 if (!fs || !validName(path)){
563 fail(FileError.ENCODING_ERR);
564 return;
565 }
566 if (!path || (new RegExp('/[^/]*/?$')).test(path)) {
567 win(new DirectoryEntry(fs.root.name, fs.root.fullPath, fs.name, fs.makeNativeURL(fs.root.fullPath)));
568 return;
569 }
570
571 var parpath = path.replace(new RegExp('/[^/]+/?$','g'),'');
572 var parname = path.substr(parpath.length);
573 var fullPath = cordovaPathToNative(fs.winpath + parpath);
574
575 var result = new DirectoryEntry(parname, parpath, fs.name, fs.makeNativeURL(parpath));
576 getFolderFromPathAsync(fullPath).done(
577 function () { win(result); },
578 function () { fail(FileError.INVALID_STATE_ERR); }
579 );
580 },
581
582 readAsText: function (win, fail, args) {
583
584 var url = args[0],
585 enc = args[1],
586 startPos = args[2],
587 endPos = args[3];
588
589 var fs = getFilesystemFromURL(url);
590 var path = pathFromURL(url);
591 if (!fs){
592 fail(FileError.ENCODING_ERR);
593 return;
594 }
595 var wpath = cordovaPathToNative(sanitize(fs.winpath + path));
596
597 var encoding = Windows.Storage.Streams.UnicodeEncoding.utf8;
598 if (enc == 'Utf16LE' || enc == 'utf16LE') {
599 encoding = Windows.Storage.Streams.UnicodeEncoding.utf16LE;
600 } else if (enc == 'Utf16BE' || enc == 'utf16BE') {
601 encoding = Windows.Storage.Streams.UnicodeEncoding.utf16BE;
602 }
603
604 getFileFromPathAsync(wpath).then(function(file) {
605 return file.openReadAsync();
606 }).then(function (stream) {
607 startPos = (startPos < 0) ? Math.max(stream.size + startPos, 0) : Math.min(stream.size, startPos);
608 endPos = (endPos < 0) ? Math.max(endPos + stream.size, 0) : Math.min(stream.size, endPos);
609 stream.seek(startPos);
610
611 var readSize = endPos - startPos,
612 buffer = new Windows.Storage.Streams.Buffer(readSize);
613
614 return stream.readAsync(buffer, readSize, Windows.Storage.Streams.InputStreamOptions.none);
615 }).done(function(buffer) {
616 try {
617 win(Windows.Security.Cryptography.CryptographicBuffer.convertBinaryToString(encoding, buffer));
618 }
619 catch (e) {
620 fail(FileError.ENCODING_ERR);
621 }
622 },function() {
623 fail(FileError.NOT_FOUND_ERR);
624 });
625 },
626
627 readAsBinaryString:function(win,fail,args) {
628 var url = args[0],
629 startPos = args[1],
630 endPos = args[2];
631
632 var fs = getFilesystemFromURL(url);
633 var path = pathFromURL(url);
634 if (!fs){
635 fail(FileError.ENCODING_ERR);
636 return;
637 }
638 var wpath = cordovaPathToNative(sanitize(fs.winpath + path));
639
640 getFileFromPathAsync(wpath).then(
641 function (storageFile) {
642 Windows.Storage.FileIO.readBufferAsync(storageFile).done(
643 function (buffer) {
644 var dataReader = Windows.Storage.Streams.DataReader.fromBuffer(buffer);
645 // var fileContent = dataReader.readString(buffer.length);
646 var byteArray = new Uint8Array(buffer.length),
647 byteString = "";
648 dataReader.readBytes(byteArray);
649 dataReader.close();
650 for (var i = 0; i < byteArray.length; i++) {
651 var charByte = byteArray[i];
652 // var charRepresentation = charByte <= 127 ? String.fromCharCode(charByte) : charByte.toString(16);
653 var charRepresentation = String.fromCharCode(charByte);
654 byteString += charRepresentation;
655 }
656 win(byteString.slice(startPos, endPos));
657 }
658 );
659 }, function () {
660 fail(FileError.NOT_FOUND_ERR);
661 }
662 );
663 },
664
665 readAsArrayBuffer:function(win,fail,args) {
666 var url = args[0];
667 var fs = getFilesystemFromURL(url);
668 var path = pathFromURL(url);
669 if (!fs){
670 fail(FileError.ENCODING_ERR);
671 return;
672 }
673 var wpath = cordovaPathToNative(sanitize(fs.winpath + path));
674
675 getFileFromPathAsync(wpath).then(
676 function (storageFile) {
677 var blob = MSApp.createFileFromStorageFile(storageFile);
678 var url = URL.createObjectURL(blob, { oneTimeOnly: true });
679 var xhr = new XMLHttpRequest();
680 xhr.open("GET", url, true);
681 xhr.responseType = 'arraybuffer';
682 xhr.onload = function () {
683 var resultArrayBuffer = xhr.response;
684 // get start and end position of bytes in buffer to be returned
685 var startPos = args[1] || 0,
686 endPos = args[2] || resultArrayBuffer.length;
687 // if any of them is specified, we'll slice output array
688 if (startPos !== 0 || endPos !== resultArrayBuffer.length) {
689 // slice method supported only on Windows 8.1, so we need to check if it's available
690 // see http://msdn.microsoft.com/en-us/library/ie/dn641192(v=vs.94).aspx
691 if (resultArrayBuffer.slice) {
692 resultArrayBuffer = resultArrayBuffer.slice(startPos, endPos);
693 } else {
694 // if slice isn't available, we'll use workaround method
695 var tempArray = new Uint8Array(resultArrayBuffer),
696 resBuffer = new ArrayBuffer(endPos - startPos),
697 resArray = new Uint8Array(resBuffer);
698
699 for (var i = 0; i < resArray.length; i++) {
700 resArray[i] = tempArray[i + startPos];
701 }
702 resultArrayBuffer = resBuffer;
703 }
704 }
705 win(resultArrayBuffer);
706 };
707 xhr.send();
708 }, function () {
709 fail(FileError.NOT_FOUND_ERR);
710 }
711 );
712 },
713
714 readAsDataURL: function (win, fail, args) {
715 var url = args[0];
716 var fs = getFilesystemFromURL(url);
717 var path = pathFromURL(url);
718 if (!fs){
719 fail(FileError.ENCODING_ERR);
720 return;
721 }
722 var wpath = cordovaPathToNative(sanitize(fs.winpath + path));
723
724 getFileFromPathAsync(wpath).then(
725 function (storageFile) {
726 Windows.Storage.FileIO.readBufferAsync(storageFile).done(
727 function (buffer) {
728 var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
729 //the method encodeToBase64String will add "77u/" as a prefix, so we should remove it
730 if(String(strBase64).substr(0,4) == "77u/") {
731 strBase64 = strBase64.substr(4);
732 }
733 var mediaType = storageFile.contentType;
734 var result = "data:" + mediaType + ";base64," + strBase64;
735 win(result);
736 }
737 );
738 }, function () {
739 fail(FileError.NOT_FOUND_ERR);
740 }
741 );
742 },
743
744 getDirectory: function (win, fail, args) {
745 var dirurl = args[0];
746 var path = args[1];
747 var options = args[2];
748
749 var fs = getFilesystemFromURL(dirurl);
750 var dirpath = pathFromURL(dirurl);
751 if (!fs || !validName(path)){
752 fail(FileError.ENCODING_ERR);
753 return;
754 }
755 var fspath = sanitize(dirpath +'/'+ path);
756 var completePath = sanitize(fs.winpath + fspath);
757
758 var name = completePath.substring(completePath.lastIndexOf('/')+1);
759
760 var wpath = cordovaPathToNative(completePath.substring(0, completePath.lastIndexOf('/')));
761
762 var flag = "";
763 if (options) {
764 flag = new Flags(options.create, options.exclusive);
765 } else {
766 flag = new Flags(false, false);
767 }
768
769 getFolderFromPathAsync(wpath).done(
770 function (storageFolder) {
771 if (flag.create === true && flag.exclusive === true) {
772 storageFolder.createFolderAsync(name, Windows.Storage.CreationCollisionOption.failIfExists).done(
773 function (storageFolder) {
774 win(new DirectoryEntry(storageFolder.name, fspath, fs.name, fs.makeNativeURL(fspath)));
775 }, function (err) {
776 fail(FileError.PATH_EXISTS_ERR);
777 }
778 );
779 } else if (flag.create === true && flag.exclusive === false) {
780 storageFolder.createFolderAsync(name, Windows.Storage.CreationCollisionOption.openIfExists).done(
781 function (storageFolder) {
782 win(new DirectoryEntry(storageFolder.name, fspath, fs.name, fs.makeNativeURL(fspath)));
783 }, function () {
784 fail(FileError.INVALID_MODIFICATION_ERR);
785 }
786 );
787 } else if (flag.create === false) {
788 storageFolder.getFolderAsync(name).done(
789 function (storageFolder) {
790 win(new DirectoryEntry(storageFolder.name, fspath, fs.name, fs.makeNativeURL(fspath)));
791 },
792 function () {
793 // check if path actually points to a file
794 storageFolder.getFileAsync(name).done(
795 function () {
796 fail(FileError.TYPE_MISMATCH_ERR);
797 }, function() {
798 fail(FileError.NOT_FOUND_ERR);
799 }
800 );
801 }
802 );
803 }
804 }, function () {
805 fail(FileError.NOT_FOUND_ERR);
806 }
807 );
808 },
809
810 remove: function (win, fail, args) {
811 var fs = getFilesystemFromURL(args[0]);
812 var path = pathFromURL(args[0]);
813 if (!fs || !validName(path)){
814 fail(FileError.ENCODING_ERR);
815 return;
816 }
817
818 // FileSystem root can't be removed!
819 if (!path || path=='/'){
820 fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
821 return;
822 }
823 var fullPath = cordovaPathToNative(fs.winpath + path);
824
825 getFileFromPathAsync(fullPath).then(
826 function (storageFile) {
827 storageFile.deleteAsync().done(win, function () {
828 fail(FileError.INVALID_MODIFICATION_ERR);
829 });
830 },
831 function () {
832 getFolderFromPathAsync(fullPath).done(
833 function (sFolder) {
834 sFolder.getFilesAsync()
835 // check for files
836 .then(function(fileList) {
837 if (fileList) {
838 if (fileList.length === 0) {
839 return sFolder.getFoldersAsync();
840 } else {
841 fail(FileError.INVALID_MODIFICATION_ERR);
842 }
843 }
844 })
845 // check for folders
846 .done(function (folderList) {
847 if (folderList) {
848 if (folderList.length === 0) {
849 sFolder.deleteAsync().done(
850 win,
851 function () {
852 fail(FileError.INVALID_MODIFICATION_ERR);
853 }
854 );
855 } else {
856 fail(FileError.INVALID_MODIFICATION_ERR);
857 }
858 }
859 });
860 },
861 function () {
862 fail(FileError.NOT_FOUND_ERR);
863 }
864 );
865 }
866 );
867 },
868
869 removeRecursively: function (successCallback, fail, args) {
870
871 var fs = getFilesystemFromURL(args[0]);
872 var path = pathFromURL(args[0]);
873 if (!fs || !validName(path)){
874 fail(FileError.ENCODING_ERR);
875 return;
876 }
877
878 // FileSystem root can't be removed!
879 if (!path || path=='/'){
880 fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
881 return;
882 }
883 var fullPath = cordovaPathToNative(fs.winpath + path);
884
885 getFolderFromPathAsync(fullPath).done(function (storageFolder) {
886 storageFolder.deleteAsync().done(function (res) {
887 successCallback(res);
888 }, function (err) {
889 fail(err);
890 });
891
892 }, function () {
893 fail(FileError.FILE_NOT_FOUND_ERR);
894 });
895 },
896
897 getFile: function (win, fail, args) {
898
899 var dirurl = args[0];
900 var path = args[1];
901 var options = args[2];
902
903 var fs = getFilesystemFromURL(dirurl);
904 var dirpath = pathFromURL(dirurl);
905 if (!fs || !validName(path)){
906 fail(FileError.ENCODING_ERR);
907 return;
908 }
909 var fspath = sanitize(dirpath +'/'+ path);
910 var completePath = sanitize(fs.winpath + fspath);
911
912 var fileName = completePath.substring(completePath.lastIndexOf('/')+1);
913
914 var wpath = cordovaPathToNative(completePath.substring(0, completePath.lastIndexOf('/')));
915
916 var flag = "";
917 if (options !== null) {
918 flag = new Flags(options.create, options.exclusive);
919 } else {
920 flag = new Flags(false, false);
921 }
922
923 getFolderFromPathAsync(wpath).done(
924 function (storageFolder) {
925 if (flag.create === true && flag.exclusive === true) {
926 storageFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.failIfExists).done(
927 function (storageFile) {
928 win(new FileEntry(storageFile.name, fspath, fs.name, fs.makeNativeURL(fspath)));
929 }, function () {
930 fail(FileError.PATH_EXISTS_ERR);
931 }
932 );
933 } else if (flag.create === true && flag.exclusive === false) {
934 storageFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.openIfExists).done(
935 function (storageFile) {
936 win(new FileEntry(storageFile.name, fspath, fs.name, fs.makeNativeURL(fspath)));
937 }, function () {
938 fail(FileError.INVALID_MODIFICATION_ERR);
939 }
940 );
941 } else if (flag.create === false) {
942 storageFolder.getFileAsync(fileName).done(
943 function (storageFile) {
944 win(new FileEntry(storageFile.name, fspath, fs.name, fs.makeNativeURL(fspath)));
945 }, function () {
946 // check if path actually points to a folder
947 storageFolder.getFolderAsync(fileName).done(
948 function () {
949 fail(FileError.TYPE_MISMATCH_ERR);
950 }, function () {
951 fail(FileError.NOT_FOUND_ERR);
952 });
953 }
954 );
955 }
956 }, function (err) {
957 fail(
958 err.number == WinError.accessDenied?
959 FileError.SECURITY_ERR:
960 FileError.NOT_FOUND_ERR
961 );
962 }
963 );
964 },
965
966 readEntries: function (win, fail, args) { // ["fullPath"]
967 var fs = getFilesystemFromURL(args[0]);
968 var path = pathFromURL(args[0]);
969 if (!fs || !validName(path)){
970 fail(FileError.ENCODING_ERR);
971 return;
972 }
973 var fullPath = cordovaPathToNative(fs.winpath + path);
974
975 var result = [];
976
977 getFolderFromPathAsync(fullPath).done(function (storageFolder) {
978 var promiseArr = [];
979 var index = 0;
980 promiseArr[index++] = storageFolder.getFilesAsync().then(function (fileList) {
981 if (fileList !== null) {
982 for (var i = 0; i < fileList.length; i++) {
983 var fspath = getFsPathForWinPath(fs, fileList[i].path);
984 if (!fspath) {
985 fail(FileError.NOT_FOUND_ERR);
986 return;
987 }
988 result.push(new FileEntry(fileList[i].name, fspath, fs.name, fs.makeNativeURL(fspath)));
989 }
990 }
991 });
992 promiseArr[index++] = storageFolder.getFoldersAsync().then(function (folderList) {
993 if (folderList !== null) {
994 for (var j = 0; j < folderList.length; j++) {
995 var fspath = getFsPathForWinPath(fs, folderList[j].path);
996 if (!fspath) {
997 fail(FileError.NOT_FOUND_ERR);
998 return;
999 }
1000 result.push(new DirectoryEntry(folderList[j].name, fspath, fs.name, fs.makeNativeURL(fspath)));
1001 }
1002 }
1003 });
1004 WinJS.Promise.join(promiseArr).then(function () {
1005 win(result);
1006 });
1007
1008 }, function () { fail(FileError.NOT_FOUND_ERR); });
1009 },
1010
1011 write: function (win, fail, args) {
1012
1013 var url = args[0],
1014 data = args[1],
1015 position = args[2],
1016 isBinary = args[3];
1017
1018 var fs = getFilesystemFromURL(url);
1019 var path = pathFromURL(url);
1020 if (!fs){
1021 fail(FileError.ENCODING_ERR);
1022 return;
1023 }
1024 var completePath = sanitize(fs.winpath + path);
1025 var fileName = completePath.substring(completePath.lastIndexOf('/')+1);
1026 var dirpath = completePath.substring(0,completePath.lastIndexOf('/'));
1027 var wpath = cordovaPathToNative(dirpath);
1028
1029 function getWriteMethodForData(data, isBinary) {
1030
1031 if (data instanceof Blob) {
1032 return writeBlobAsync;
1033 }
1034
1035 if (data instanceof ArrayBuffer) {
1036 return writeArrayBufferAsync;
1037 }
1038
1039 if (isBinary) {
1040 return writeBytesAsync;
1041 }
1042
1043 if (typeof data === 'string') {
1044 return writeTextAsync;
1045 }
1046
1047 throw new Error('Unsupported data type for write method');
1048 }
1049
1050 var writePromise = getWriteMethodForData(data, isBinary);
1051
1052 getFolderFromPathAsync(wpath).done(
1053 function (storageFolder) {
1054 storageFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.openIfExists).done(
1055 function (storageFile) {
1056 writePromise(storageFile, data, position).done(
1057 function (bytesWritten) {
1058 var written = bytesWritten || data.length;
1059 win(written);
1060 },
1061 function () {
1062 fail(FileError.INVALID_MODIFICATION_ERR);
1063 }
1064 );
1065 },
1066 function () {
1067 fail(FileError.INVALID_MODIFICATION_ERR);
1068 }
1069 );
1070
1071 },
1072 function () {
1073 fail(FileError.NOT_FOUND_ERR);
1074 }
1075 );
1076 },
1077
1078 truncate: function (win, fail, args) { // ["fileName","size"]
1079 var url = args[0];
1080 var size = args[1];
1081
1082 var fs = getFilesystemFromURL(url);
1083 var path = pathFromURL(url);
1084 if (!fs){
1085 fail(FileError.ENCODING_ERR);
1086 return;
1087 }
1088 var completePath = sanitize(fs.winpath + path);
1089 var wpath = cordovaPathToNative(completePath);
1090 var dirwpath = cordovaPathToNative(completePath.substring(0,completePath.lastIndexOf('/')));
1091
1092 getFileFromPathAsync(wpath).done(function(storageFile){
1093 //the current length of the file.
1094 var leng = 0;
1095
1096 storageFile.getBasicPropertiesAsync().then(function (basicProperties) {
1097 leng = basicProperties.size;
1098 if (Number(size) >= leng) {
1099 win(this.length);
1100 return;
1101 }
1102 if (Number(size) >= 0) {
1103 Windows.Storage.FileIO.readTextAsync(storageFile, Windows.Storage.Streams.UnicodeEncoding.utf8).then(function (fileContent) {
1104 fileContent = fileContent.substr(0, size);
1105 var name = storageFile.name;
1106 storageFile.deleteAsync().then(function () {
1107 return getFolderFromPathAsync(dirwpath);
1108 }).done(function (storageFolder) {
1109 storageFolder.createFileAsync(name).then(function (newStorageFile) {
1110 Windows.Storage.FileIO.writeTextAsync(newStorageFile, fileContent).done(function () {
1111 win(String(fileContent).length);
1112 }, function () {
1113 fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
1114 });
1115 }, function() {
1116 fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
1117 });
1118 });
1119 }, function () { fail(FileError.NOT_FOUND_ERR); });
1120 }
1121 });
1122 }, function () { fail(FileError.NOT_FOUND_ERR); });
1123 },
1124
1125 copyTo: function (success, fail, args) { // ["fullPath","parent", "newName"]
1126 transport(success, fail, args,
1127 {
1128 fileOp:function(file,folder,name,coll) {
1129 return file.copyAsync(folder,name,coll);
1130 },
1131 folderOp:function(src,dst,name) {
1132 return copyFolder(src,dst,name);
1133 }}
1134 );
1135 },
1136
1137 moveTo: function (success, fail, args) {
1138 transport(success, fail, args,
1139 {
1140 fileOp:function(file,folder,name,coll) {
1141 return file.moveAsync(folder,name,coll);
1142 },
1143 folderOp:function(src,dst,name) {
1144 return moveFolder(src,dst,name);
1145 }}
1146 );
1147 },
1148 tempFileSystem:null,
1149
1150 persistentFileSystem:null,
1151
1152 requestFileSystem: function (win, fail, args) {
1153
1154 var type = args[0];
1155 var size = args[1];
1156 var MAX_SIZE = 10000000000;
1157 if (size > MAX_SIZE) {
1158 fail(FileError.QUOTA_EXCEEDED_ERR);
1159 return;
1160 }
1161
1162 var fs;
1163 switch (type) {
1164 case LocalFileSystem.TEMPORARY:
1165 fs = getFS('temporary');
1166 break;
1167 case LocalFileSystem.PERSISTENT:
1168 fs = getFS('persistent');
1169 break;
1170 }
1171 if (fs)
1172 win(fs);
1173 else
1174 fail(FileError.NOT_FOUND_ERR);
1175 },
1176
1177 resolveLocalFileSystemURI: function (success, fail, args) {
1178
1179 var uri = args[0];
1180
1181 var path = pathFromURL(uri);
1182 var fs = getFilesystemFromURL(uri);
1183 if (!fs || !validName(path)) {
1184 fail(FileError.ENCODING_ERR);
1185 return;
1186 }
1187 if (path.indexOf(fs.winpath) === 0)
1188 path=path.substr(fs.winpath.length);
1189 var abspath = cordovaPathToNative(fs.winpath+path);
1190
1191 getFileFromPathAsync(abspath).done(
1192 function (storageFile) {
1193 success(new FileEntry(storageFile.name, path, fs.name, fs.makeNativeURL(path)));
1194 }, function () {
1195 getFolderFromPathAsync(abspath).done(
1196 function (storageFolder) {
1197 success(new DirectoryEntry(storageFolder.name, path, fs.name,fs.makeNativeURL(path)));
1198 }, function () {
1199 fail(FileError.NOT_FOUND_ERR);
1200 }
1201 );
1202 }
1203 );
1204 }
1205
1206
1207};
1208
1209require("cordova/exec/proxy").add("File",module.exports);