blob: 030703210261f366158bbfe214f4c85c16d409a6 [file] [log] [blame]
/*
*
* 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.
*
*/
/* global Windows, WinJS, MSApp */
var File = require('./File');
var FileError = require('./FileError');
var Flags = require('./Flags');
var FileSystem = require('./FileSystem');
var LocalFileSystem = require('./LocalFileSystem');
var utils = require('cordova/utils');
function Entry (isFile, isDirectory, name, fullPath, filesystemName, nativeURL) {
this.isFile = !!isFile;
this.isDirectory = !!isDirectory;
this.name = name || '';
this.fullPath = fullPath || '';
this.filesystemName = filesystemName || null;
this.nativeURL = nativeURL || null;
}
var FileEntry = function (name, fullPath, filesystemName, nativeURL) {
FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath, filesystemName, nativeURL]);
};
utils.extend(FileEntry, Entry);
var DirectoryEntry = function (name, fullPath, filesystemName, nativeURL) {
DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath, filesystemName, nativeURL);
};
utils.extend(DirectoryEntry, Entry);
var getFolderFromPathAsync = Windows.Storage.StorageFolder.getFolderFromPathAsync;
var getFileFromPathAsync = Windows.Storage.StorageFile.getFileFromPathAsync;
function writeBytesAsync (storageFile, data, position) {
return storageFile.openAsync(Windows.Storage.FileAccessMode.readWrite)
.then(function (output) {
output.seek(position);
var dataWriter = new Windows.Storage.Streams.DataWriter(output);
dataWriter.writeBytes(data);
return dataWriter.storeAsync().then(function (size) {
output.size = position + size;
return dataWriter.flushAsync().then(function () {
output.close();
return size;
});
});
});
}
function writeTextAsync (storageFile, data, position) {
return storageFile.openAsync(Windows.Storage.FileAccessMode.readWrite)
.then(function (output) {
output.seek(position);
var dataWriter = new Windows.Storage.Streams.DataWriter(output);
dataWriter.writeString(data);
return dataWriter.storeAsync().then(function (size) {
output.size = position + size;
return dataWriter.flushAsync().then(function () {
output.close();
return size;
});
});
});
}
function writeBlobAsync (storageFile, data, position) {
return storageFile.openAsync(Windows.Storage.FileAccessMode.readWrite)
.then(function (output) {
output.seek(position);
var dataSize = data.size;
var input = (data.detachStream || data.msDetachStream).call(data);
// Copy the stream from the blob to the File stream
return Windows.Storage.Streams.RandomAccessStream.copyAsync(input, output)
.then(function () {
output.size = position + dataSize;
return output.flushAsync().then(function () {
input.close();
output.close();
return dataSize;
});
});
});
}
function writeArrayBufferAsync (storageFile, data, position) {
return writeBlobAsync(storageFile, new Blob([data]), position); // eslint-disable-line no-undef
}
function cordovaPathToNative (path) {
// turn / into \\
var cleanPath = path.replace(/\//g, '\\');
// turn \\ into \
cleanPath = cleanPath.replace(/\\+/g, '\\');
return cleanPath;
}
function nativePathToCordova (path) {
var cleanPath = path.replace(/\\/g, '/');
return cleanPath;
}
var driveRE = new RegExp('^[/]*([A-Z]:)');
var invalidNameRE = /[\\?*|"<>:]/;
function validName (name) {
return !invalidNameRE.test(name.replace(driveRE, ''));
}
function sanitize (path) {
var slashesRE = new RegExp('/{2,}', 'g');
var components = path.replace(slashesRE, '/').split(/\/+/);
// Remove double dots, use old school array iteration instead of RegExp
// since it is impossible to debug them
for (var index = 0; index < components.length; ++index) {
if (components[index] === '..') {
components.splice(index, 1);
if (index > 0) {
// if we're not in the start of array then remove preceeding path component,
// In case if relative path points above the root directory, just ignore double dots
// See file.spec.111 should not traverse above above the root directory for test case
components.splice(index - 1, 1);
--index;
}
}
}
return components.join('/');
}
var WinFS = function (name, root) {
this.winpath = root.winpath;
if (this.winpath && !/\/$/.test(this.winpath)) {
this.winpath += '/';
}
this.makeNativeURL = function (path) {
// CB-11848: This RE supposed to match all leading slashes in sanitized path.
// Removing leading slash to avoid duplicating because this.root.nativeURL already has trailing slash
var regLeadingSlashes = /^\/*/;
var sanitizedPath = sanitize(path.replace(':', '%3A')).replace(regLeadingSlashes, '');
return FileSystem.encodeURIPath(this.root.nativeURL + sanitizedPath);
};
root.fullPath = '/';
if (!root.nativeURL) { root.nativeURL = 'file://' + sanitize(this.winpath + root.fullPath).replace(':', '%3A'); }
WinFS.__super__.constructor.call(this, name, root);
};
utils.extend(WinFS, FileSystem);
WinFS.prototype.__format__ = function (fullPath) {
var path = sanitize('/' + this.name + (fullPath[0] === '/' ? '' : '/') + FileSystem.encodeURIPath(fullPath));
return 'cdvfile://localhost' + path;
};
var windowsPaths = {
dataDirectory: 'ms-appdata:///local/',
cacheDirectory: 'ms-appdata:///temp/',
tempDirectory: 'ms-appdata:///temp/',
syncedDataDirectory: 'ms-appdata:///roaming/',
applicationDirectory: 'ms-appx:///',
applicationStorageDirectory: 'ms-appx:///'
};
var AllFileSystems;
function getAllFS () {
if (!AllFileSystems) {
AllFileSystems = {
persistent: Object.freeze(new WinFS('persistent', {
name: 'persistent',
nativeURL: 'ms-appdata:///local',
winpath: nativePathToCordova(Windows.Storage.ApplicationData.current.localFolder.path)
})),
temporary: Object.freeze(new WinFS('temporary', {
name: 'temporary',
nativeURL: 'ms-appdata:///temp',
winpath: nativePathToCordova(Windows.Storage.ApplicationData.current.temporaryFolder.path)
})),
application: Object.freeze(new WinFS('application', {
name: 'application',
nativeURL: 'ms-appx:///',
winpath: nativePathToCordova(Windows.ApplicationModel.Package.current.installedLocation.path)
})),
root: Object.freeze(new WinFS('root', {
name: 'root',
// nativeURL: 'file:///'
winpath: ''
}))
};
}
return AllFileSystems;
}
function getFS (name) {
return getAllFS()[name];
}
FileSystem.prototype.__format__ = function (fullPath) {
return getFS(this.name).__format__(fullPath);
};
require('./fileSystems').getFs = function (name, callback) {
setTimeout(function () { callback(getFS(name)); });
};
function getFilesystemFromPath (path) {
var res;
var allfs = getAllFS();
Object.keys(allfs).some(function (fsn) {
var fs = allfs[fsn];
if (path.indexOf(fs.winpath) === 0) { res = fs; }
return res;
});
return res;
}
var msapplhRE = new RegExp('^ms-appdata://localhost/');
function pathFromURL (url) {
url = url.replace(msapplhRE, 'ms-appdata:///');
var path = decodeURIComponent(url);
// support for file name with parameters
if (/\?/g.test(path)) {
path = String(path).split('?')[0];
}
if (path.indexOf('file:/') === 0) {
if (path.indexOf('file://') !== 0) {
url = 'file:///' + url.substr(6);
}
}
['file://', 'ms-appdata:///', 'ms-appx://', 'cdvfile://localhost/'].every(function (p) {
if (path.indexOf(p) !== 0) { return true; }
var thirdSlash = path.indexOf('/', p.length);
if (thirdSlash < 0) {
path = '';
} else {
path = sanitize(path.substr(thirdSlash));
}
});
return path.replace(driveRE, '$1');
}
function getFilesystemFromURL (url) {
url = url.replace(msapplhRE, 'ms-appdata:///');
var res;
if (url.indexOf('file:/') === 0) { res = getFilesystemFromPath(pathFromURL(url)); } else {
var allfs = getAllFS();
Object.keys(allfs).every(function (fsn) {
var fs = allfs[fsn];
if (url.indexOf(fs.root.nativeURL) === 0 ||
url.indexOf('cdvfile://localhost/' + fs.name + '/') === 0) {
res = fs;
return false;
}
return true;
});
}
return res;
}
function getFsPathForWinPath (fs, wpath) {
var path = nativePathToCordova(wpath);
if (path.indexOf(fs.winpath) !== 0) { return null; }
return path.replace(fs.winpath, '/');
}
var WinError = {
invalidArgument: -2147024809,
fileNotFound: -2147024894,
accessDenied: -2147024891
};
function openPath (path, ops) {
ops = ops || {};
return new WinJS.Promise(function (complete, failed) {
getFileFromPathAsync(path).done(
function (file) {
complete({ file: file });
},
function (err) {
if (err.number !== WinError.fileNotFound && err.number !== WinError.invalidArgument) { failed(FileError.NOT_READABLE_ERR); }
getFolderFromPathAsync(path)
.done(
function (dir) {
if (!ops.getContent) { complete({ folder: dir }); } else {
WinJS.Promise.join({
files: dir.getFilesAsync(),
folders: dir.getFoldersAsync()
}).done(
function (a) {
complete({
folder: dir,
files: a.files,
folders: a.folders
});
},
function () {
failed(FileError.NOT_READABLE_ERR);
}
);
}
},
function (err) {
if (err.number === WinError.fileNotFound || err.number === WinError.invalidArgument) { complete({}); } else { failed(FileError.NOT_READABLE_ERR); }
}
);
}
);
});
}
function copyFolder (src, dst, name) {
name = name || src.name;
return new WinJS.Promise(function (complete, failed) {
WinJS.Promise.join({
fld: dst.createFolderAsync(name, Windows.Storage.CreationCollisionOption.openIfExists),
files: src.getFilesAsync(),
folders: src.getFoldersAsync()
}).done(
function (the) {
if (!(the.files.length || the.folders.length)) {
complete();
return;
}
var todo = the.files.length;
var copyfolders = function () {
if (!(todo--)) {
complete();
return;
}
copyFolder(the.folders[todo], dst).done(function () { copyfolders(); }, failed);
};
var copyfiles = function () {
if (!(todo--)) {
todo = the.folders.length;
copyfolders();
return;
}
the.files[todo].copyAsync(the.fld).done(function () { copyfiles(); }, failed);
};
copyfiles();
},
failed
);
});
}
function moveFolder (src, dst, name) {
name = name || src.name;
return new WinJS.Promise(function (complete, failed) {
WinJS.Promise.join({
fld: dst.createFolderAsync(name, Windows.Storage.CreationCollisionOption.openIfExists),
files: src.getFilesAsync(),
folders: src.getFoldersAsync()
}).done(
function (the) {
if (!(the.files.length || the.folders.length)) {
complete();
return;
}
var todo = the.files.length;
var movefolders = function () {
if (!(todo--)) {
src.deleteAsync().done(complete, failed);
return;
}
moveFolder(the.folders[todo], the.fld).done(movefolders, failed);
};
var movefiles = function () {
if (!(todo--)) {
todo = the.folders.length;
movefolders();
return;
}
the.files[todo].moveAsync(the.fld).done(function () { movefiles(); }, failed);
};
movefiles();
},
failed
);
});
}
function transport (success, fail, args, ops) { // ["fullPath","parent", "newName"]
var src = args[0];
var parent = args[1];
var name = args[2];
var srcFS = getFilesystemFromURL(src);
var dstFS = getFilesystemFromURL(parent);
var srcPath = pathFromURL(src);
var dstPath = pathFromURL(parent);
if (!(srcFS && dstFS && validName(name))) {
fail(FileError.ENCODING_ERR);
return;
}
var srcWinPath = cordovaPathToNative(sanitize(srcFS.winpath + srcPath));
var dstWinPath = cordovaPathToNative(sanitize(dstFS.winpath + dstPath));
var tgtFsPath = sanitize(dstPath + '/' + name);
var tgtWinPath = cordovaPathToNative(sanitize(dstFS.winpath + dstPath + '/' + name));
if (srcWinPath === dstWinPath || srcWinPath === tgtWinPath) {
fail(FileError.INVALID_MODIFICATION_ERR);
return;
}
WinJS.Promise.join({
src: openPath(srcWinPath),
dst: openPath(dstWinPath),
tgt: openPath(tgtWinPath, { getContent: true })
}).done(
function (the) {
if ((!the.dst.folder) || !(the.src.folder || the.src.file)) {
fail(FileError.NOT_FOUND_ERR);
return;
}
if ((the.src.folder && the.tgt.file) ||
(the.src.file && the.tgt.folder) ||
(the.tgt.folder && (the.tgt.files.length || the.tgt.folders.length))) {
fail(FileError.INVALID_MODIFICATION_ERR);
return;
}
if (the.src.file) {
ops.fileOp(the.src.file, the.dst.folder, name, Windows.Storage.NameCollisionOption.replaceExisting)
.done(
function (storageFile) {
success(new FileEntry(
name,
tgtFsPath,
dstFS.name,
dstFS.makeNativeURL(tgtFsPath)
));
},
function () {
fail(FileError.INVALID_MODIFICATION_ERR);
}
);
} else {
ops.folderOp(the.src.folder, the.dst.folder, name).done(
function () {
success(new DirectoryEntry(
name,
tgtFsPath,
dstFS.name,
dstFS.makeNativeURL(tgtFsPath)
));
},
function () {
fail(FileError.INVALID_MODIFICATION_ERR);
}
);
}
},
function () {
fail(FileError.INVALID_MODIFICATION_ERR);
}
);
}
module.exports = {
requestAllFileSystems: function () {
return getAllFS();
},
requestAllPaths: function (success) {
success(windowsPaths);
},
getFileMetadata: function (success, fail, args) {
module.exports.getMetadata(success, fail, args);
},
getMetadata: function (success, fail, args) {
var fs = getFilesystemFromURL(args[0]);
var path = pathFromURL(args[0]);
if (!fs || !validName(path)) {
fail(FileError.ENCODING_ERR);
return;
}
var fullPath = cordovaPathToNative(fs.winpath + path);
var getMetadataForFile = function (storageFile) {
storageFile.getBasicPropertiesAsync().then(
function (basicProperties) {
success(new File(storageFile.name, storageFile.path, storageFile.fileType, basicProperties.dateModified, basicProperties.size));
}, function () {
fail(FileError.NOT_READABLE_ERR);
}
);
};
var getMetadataForFolder = function (storageFolder) {
storageFolder.getBasicPropertiesAsync().then(
function (basicProperties) {
var metadata = {
size: basicProperties.size,
lastModifiedDate: basicProperties.dateModified
};
success(metadata);
},
function () {
fail(FileError.NOT_READABLE_ERR);
}
);
};
getFileFromPathAsync(fullPath).then(getMetadataForFile,
function () {
getFolderFromPathAsync(fullPath).then(getMetadataForFolder,
function () {
fail(FileError.NOT_FOUND_ERR);
}
);
}
);
},
getParent: function (win, fail, args) { // ["fullPath"]
var fs = getFilesystemFromURL(args[0]);
var path = pathFromURL(args[0]);
if (!fs || !validName(path)) {
fail(FileError.ENCODING_ERR);
return;
}
if (!path || (new RegExp('/[^/]*/?$')).test(path)) {
win(new DirectoryEntry(fs.root.name, fs.root.fullPath, fs.name, fs.makeNativeURL(fs.root.fullPath)));
return;
}
var parpath = path.replace(new RegExp('/[^/]+/?$', 'g'), '');
var parname = path.substr(parpath.length);
var fullPath = cordovaPathToNative(fs.winpath + parpath);
var result = new DirectoryEntry(parname, parpath, fs.name, fs.makeNativeURL(parpath));
getFolderFromPathAsync(fullPath).done(
function () { win(result); },
function () { fail(FileError.INVALID_STATE_ERR); }
);
},
readAsText: function (win, fail, args) {
var url = args[0];
var enc = args[1];
var startPos = args[2];
var endPos = args[3];
var fs = getFilesystemFromURL(url);
var path = pathFromURL(url);
if (!fs) {
fail(FileError.ENCODING_ERR);
return;
}
var wpath = cordovaPathToNative(sanitize(fs.winpath + path));
var encoding = Windows.Storage.Streams.UnicodeEncoding.utf8;
if (enc === 'Utf16LE' || enc === 'utf16LE') {
encoding = Windows.Storage.Streams.UnicodeEncoding.utf16LE;
} else if (enc === 'Utf16BE' || enc === 'utf16BE') {
encoding = Windows.Storage.Streams.UnicodeEncoding.utf16BE;
}
getFileFromPathAsync(wpath).then(function (file) {
return file.openReadAsync();
}).then(function (stream) {
startPos = (startPos < 0) ? Math.max(stream.size + startPos, 0) : Math.min(stream.size, startPos);
endPos = (endPos < 0) ? Math.max(endPos + stream.size, 0) : Math.min(stream.size, endPos);
stream.seek(startPos);
var readSize = endPos - startPos;
var buffer = new Windows.Storage.Streams.Buffer(readSize);
return stream.readAsync(buffer, readSize, Windows.Storage.Streams.InputStreamOptions.none);
}).done(function (buffer) {
try {
win(Windows.Security.Cryptography.CryptographicBuffer.convertBinaryToString(encoding, buffer));
} catch (e) {
fail(FileError.ENCODING_ERR);
}
}, function () {
fail(FileError.NOT_FOUND_ERR);
});
},
readAsBinaryString: function (win, fail, args) {
var url = args[0];
var startPos = args[1];
var endPos = args[2];
var fs = getFilesystemFromURL(url);
var path = pathFromURL(url);
if (!fs) {
fail(FileError.ENCODING_ERR);
return;
}
var wpath = cordovaPathToNative(sanitize(fs.winpath + path));
getFileFromPathAsync(wpath).then(
function (storageFile) {
Windows.Storage.FileIO.readBufferAsync(storageFile).done(
function (buffer) {
var dataReader = Windows.Storage.Streams.DataReader.fromBuffer(buffer);
// var fileContent = dataReader.readString(buffer.length);
var byteArray = new Uint8Array(buffer.length);
var byteString = '';
dataReader.readBytes(byteArray);
dataReader.close();
for (var i = 0; i < byteArray.length; i++) {
var charByte = byteArray[i];
// var charRepresentation = charByte <= 127 ? String.fromCharCode(charByte) : charByte.toString(16);
var charRepresentation = String.fromCharCode(charByte);
byteString += charRepresentation;
}
win(byteString.slice(startPos, endPos));
}
);
}, function () {
fail(FileError.NOT_FOUND_ERR);
}
);
},
readAsArrayBuffer: function (win, fail, args) {
var url = args[0];
var fs = getFilesystemFromURL(url);
var path = pathFromURL(url);
if (!fs) {
fail(FileError.ENCODING_ERR);
return;
}
var wpath = cordovaPathToNative(sanitize(fs.winpath + path));
getFileFromPathAsync(wpath).then(
function (storageFile) {
var blob = MSApp.createFileFromStorageFile(storageFile);
var url = URL.createObjectURL(blob, { oneTimeOnly: true }); // eslint-disable-line no-undef
var xhr = new XMLHttpRequest(); // eslint-disable-line no-undef
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
var resultArrayBuffer = xhr.response;
// get start and end position of bytes in buffer to be returned
var startPos = args[1] || 0;
var endPos = args[2] || resultArrayBuffer.length;
// if any of them is specified, we'll slice output array
if (startPos !== 0 || endPos !== resultArrayBuffer.length) {
// slice method supported only on Windows 8.1, so we need to check if it's available
// see http://msdn.microsoft.com/en-us/library/ie/dn641192(v=vs.94).aspx
if (resultArrayBuffer.slice) {
resultArrayBuffer = resultArrayBuffer.slice(startPos, endPos);
} else {
// if slice isn't available, we'll use workaround method
var tempArray = new Uint8Array(resultArrayBuffer);
var resBuffer = new ArrayBuffer(endPos - startPos);
var resArray = new Uint8Array(resBuffer);
for (var i = 0; i < resArray.length; i++) {
resArray[i] = tempArray[i + startPos];
}
resultArrayBuffer = resBuffer;
}
}
win(resultArrayBuffer);
};
xhr.send();
}, function () {
fail(FileError.NOT_FOUND_ERR);
}
);
},
readAsDataURL: function (win, fail, args) {
var url = args[0];
var fs = getFilesystemFromURL(url);
var path = pathFromURL(url);
if (!fs) {
fail(FileError.ENCODING_ERR);
return;
}
var wpath = cordovaPathToNative(sanitize(fs.winpath + path));
getFileFromPathAsync(wpath).then(
function (storageFile) {
Windows.Storage.FileIO.readBufferAsync(storageFile).done(
function (buffer) {
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
// the method encodeToBase64String will add "77u/" as a prefix, so we should remove it
if (String(strBase64).substr(0, 4) === '77u/') {
strBase64 = strBase64.substr(4);
}
var mediaType = storageFile.contentType;
var result = 'data:' + mediaType + ';base64,' + strBase64;
win(result);
}
);
}, function () {
fail(FileError.NOT_FOUND_ERR);
}
);
},
getDirectory: function (win, fail, args) {
var dirurl = args[0];
var path = args[1];
var options = args[2];
var fs = getFilesystemFromURL(dirurl);
var dirpath = pathFromURL(dirurl);
if (!fs || !validName(path)) {
fail(FileError.ENCODING_ERR);
return;
}
var fspath = sanitize(dirpath + '/' + path);
var completePath = sanitize(fs.winpath + fspath);
var name = completePath.substring(completePath.lastIndexOf('/') + 1);
var wpath = cordovaPathToNative(completePath.substring(0, completePath.lastIndexOf('/')));
var flag = '';
if (options) {
flag = new Flags(options.create, options.exclusive);
} else {
flag = new Flags(false, false);
}
getFolderFromPathAsync(wpath).done(
function (storageFolder) {
if (flag.create === true && flag.exclusive === true) {
storageFolder.createFolderAsync(name, Windows.Storage.CreationCollisionOption.failIfExists).done(
function (storageFolder) {
win(new DirectoryEntry(storageFolder.name, fspath, fs.name, fs.makeNativeURL(fspath)));
}, function (err) { // eslint-disable-line handle-callback-err
fail(FileError.PATH_EXISTS_ERR);
}
);
} else if (flag.create === true && flag.exclusive === false) {
storageFolder.createFolderAsync(name, Windows.Storage.CreationCollisionOption.openIfExists).done(
function (storageFolder) {
win(new DirectoryEntry(storageFolder.name, fspath, fs.name, fs.makeNativeURL(fspath)));
}, function () {
fail(FileError.INVALID_MODIFICATION_ERR);
}
);
} else if (flag.create === false) {
storageFolder.getFolderAsync(name).done(
function (storageFolder) {
win(new DirectoryEntry(storageFolder.name, fspath, fs.name, fs.makeNativeURL(fspath)));
},
function () {
// check if path actually points to a file
storageFolder.getFileAsync(name).done(
function () {
fail(FileError.TYPE_MISMATCH_ERR);
}, function () {
fail(FileError.NOT_FOUND_ERR);
}
);
}
);
}
}, function () {
fail(FileError.NOT_FOUND_ERR);
}
);
},
remove: function (win, fail, args) {
var fs = getFilesystemFromURL(args[0]);
var path = pathFromURL(args[0]);
if (!fs || !validName(path)) {
fail(FileError.ENCODING_ERR);
return;
}
// FileSystem root can't be removed!
if (!path || path === '/') {
fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
return;
}
var fullPath = cordovaPathToNative(fs.winpath + path);
getFileFromPathAsync(fullPath).then(
function (storageFile) {
storageFile.deleteAsync().done(win, function () {
fail(FileError.INVALID_MODIFICATION_ERR);
});
},
function () {
getFolderFromPathAsync(fullPath).done(
function (sFolder) {
sFolder.getFilesAsync()
// check for files
.then(function (fileList) {
if (fileList) {
if (fileList.length === 0) {
return sFolder.getFoldersAsync();
} else {
fail(FileError.INVALID_MODIFICATION_ERR);
}
}
})
// check for folders
.done(function (folderList) {
if (folderList) {
if (folderList.length === 0) {
sFolder.deleteAsync().done(
win,
function () {
fail(FileError.INVALID_MODIFICATION_ERR);
}
);
} else {
fail(FileError.INVALID_MODIFICATION_ERR);
}
}
});
},
function () {
fail(FileError.NOT_FOUND_ERR);
}
);
}
);
},
removeRecursively: function (successCallback, fail, args) {
var fs = getFilesystemFromURL(args[0]);
var path = pathFromURL(args[0]);
if (!fs || !validName(path)) {
fail(FileError.ENCODING_ERR);
return;
}
// FileSystem root can't be removed!
if (!path || path === '/') {
fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
return;
}
var fullPath = cordovaPathToNative(fs.winpath + path);
getFolderFromPathAsync(fullPath).done(function (storageFolder) {
storageFolder.deleteAsync().done(function (res) {
successCallback(res);
}, function (err) {
fail(err);
});
}, function () {
fail(FileError.FILE_NOT_FOUND_ERR);
});
},
getFile: function (win, fail, args) {
var dirurl = args[0];
var path = args[1];
var options = args[2];
var fs = getFilesystemFromURL(dirurl);
var dirpath = pathFromURL(dirurl);
if (!fs || !validName(path)) {
fail(FileError.ENCODING_ERR);
return;
}
var fspath = sanitize(dirpath + '/' + path);
var completePath = sanitize(fs.winpath + fspath);
var fileName = completePath.substring(completePath.lastIndexOf('/') + 1);
var wpath = cordovaPathToNative(completePath.substring(0, completePath.lastIndexOf('/')));
var flag = '';
if (options !== null) {
flag = new Flags(options.create, options.exclusive);
} else {
flag = new Flags(false, false);
}
getFolderFromPathAsync(wpath).done(
function (storageFolder) {
if (flag.create === true && flag.exclusive === true) {
storageFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.failIfExists).done(
function (storageFile) {
win(new FileEntry(storageFile.name, fspath, fs.name, fs.makeNativeURL(fspath)));
}, function () {
fail(FileError.PATH_EXISTS_ERR);
}
);
} else if (flag.create === true && flag.exclusive === false) {
storageFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.openIfExists).done(
function (storageFile) {
win(new FileEntry(storageFile.name, fspath, fs.name, fs.makeNativeURL(fspath)));
}, function () {
fail(FileError.INVALID_MODIFICATION_ERR);
}
);
} else if (flag.create === false) {
storageFolder.getFileAsync(fileName).done(
function (storageFile) {
win(new FileEntry(storageFile.name, fspath, fs.name, fs.makeNativeURL(fspath)));
}, function () {
// check if path actually points to a folder
storageFolder.getFolderAsync(fileName).done(
function () {
fail(FileError.TYPE_MISMATCH_ERR);
}, function () {
fail(FileError.NOT_FOUND_ERR);
}
);
}
);
}
}, function (err) {
fail(
err.number === WinError.accessDenied
? FileError.SECURITY_ERR
: FileError.NOT_FOUND_ERR
);
}
);
},
readEntries: function (win, fail, args) { // ["fullPath"]
var fs = getFilesystemFromURL(args[0]);
var path = pathFromURL(args[0]);
if (!fs || !validName(path)) {
fail(FileError.ENCODING_ERR);
return;
}
var fullPath = cordovaPathToNative(fs.winpath + path);
var result = [];
getFolderFromPathAsync(fullPath).done(function (storageFolder) {
var promiseArr = [];
var index = 0;
promiseArr[index++] = storageFolder.getFilesAsync().then(function (fileList) {
if (fileList !== null) {
for (var i = 0; i < fileList.length; i++) {
var fspath = getFsPathForWinPath(fs, fileList[i].path);
if (!fspath) {
fail(FileError.NOT_FOUND_ERR);
return;
}
result.push(new FileEntry(fileList[i].name, fspath, fs.name, fs.makeNativeURL(fspath)));
}
}
});
promiseArr[index++] = storageFolder.getFoldersAsync().then(function (folderList) {
if (folderList !== null) {
for (var j = 0; j < folderList.length; j++) {
var fspath = getFsPathForWinPath(fs, folderList[j].path);
if (!fspath) {
fail(FileError.NOT_FOUND_ERR);
return;
}
result.push(new DirectoryEntry(folderList[j].name, fspath, fs.name, fs.makeNativeURL(fspath)));
}
}
});
WinJS.Promise.join(promiseArr).then(function () {
win(result);
});
}, function () { fail(FileError.NOT_FOUND_ERR); });
},
write: function (win, fail, args) {
var url = args[0];
var data = args[1];
var position = args[2];
var isBinary = args[3];
var fs = getFilesystemFromURL(url);
var path = pathFromURL(url);
if (!fs) {
fail(FileError.ENCODING_ERR);
return;
}
var completePath = sanitize(fs.winpath + path);
var fileName = completePath.substring(completePath.lastIndexOf('/') + 1);
var dirpath = completePath.substring(0, completePath.lastIndexOf('/'));
var wpath = cordovaPathToNative(dirpath);
function getWriteMethodForData (data, isBinary) {
if (data instanceof Blob) {
return writeBlobAsync;
}
if (data instanceof ArrayBuffer) {
return writeArrayBufferAsync;
}
if (isBinary) {
return writeBytesAsync;
}
if (typeof data === 'string') {
return writeTextAsync;
}
throw new Error('Unsupported data type for write method');
}
var writePromise = getWriteMethodForData(data, isBinary);
getFolderFromPathAsync(wpath).done(
function (storageFolder) {
storageFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.openIfExists).done(
function (storageFile) {
writePromise(storageFile, data, position).done(
function (bytesWritten) {
var written = bytesWritten || data.length;
win(written);
},
function () {
fail(FileError.INVALID_MODIFICATION_ERR);
}
);
},
function () {
fail(FileError.INVALID_MODIFICATION_ERR);
}
);
},
function () {
fail(FileError.NOT_FOUND_ERR);
}
);
},
truncate: function (win, fail, args) { // ["fileName","size"]
var url = args[0];
var size = args[1];
var fs = getFilesystemFromURL(url);
var path = pathFromURL(url);
if (!fs) {
fail(FileError.ENCODING_ERR);
return;
}
var completePath = sanitize(fs.winpath + path);
var wpath = cordovaPathToNative(completePath);
var dirwpath = cordovaPathToNative(completePath.substring(0, completePath.lastIndexOf('/')));
getFileFromPathAsync(wpath).done(function (storageFile) {
// the current length of the file.
var leng = 0;
storageFile.getBasicPropertiesAsync().then(function (basicProperties) {
leng = basicProperties.size;
if (Number(size) >= leng) {
win(this.length);
return;
}
if (Number(size) >= 0) {
Windows.Storage.FileIO.readTextAsync(storageFile, Windows.Storage.Streams.UnicodeEncoding.utf8).then(function (fileContent) {
fileContent = fileContent.substr(0, size);
var name = storageFile.name;
storageFile.deleteAsync().then(function () {
return getFolderFromPathAsync(dirwpath);
}).done(function (storageFolder) {
storageFolder.createFileAsync(name).then(function (newStorageFile) {
Windows.Storage.FileIO.writeTextAsync(newStorageFile, fileContent).done(function () {
win(String(fileContent).length);
}, function () {
fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
});
}, function () {
fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
});
});
}, function () { fail(FileError.NOT_FOUND_ERR); });
}
});
}, function () { fail(FileError.NOT_FOUND_ERR); });
},
copyTo: function (success, fail, args) { // ["fullPath","parent", "newName"]
transport(success, fail, args,
{
fileOp: function (file, folder, name, coll) {
return file.copyAsync(folder, name, coll);
},
folderOp: function (src, dst, name) {
return copyFolder(src, dst, name);
}
}
);
},
moveTo: function (success, fail, args) {
transport(success, fail, args,
{
fileOp: function (file, folder, name, coll) {
return file.moveAsync(folder, name, coll);
},
folderOp: function (src, dst, name) {
return moveFolder(src, dst, name);
}
}
);
},
tempFileSystem: null,
persistentFileSystem: null,
requestFileSystem: function (win, fail, args) {
var type = args[0];
var size = args[1];
var MAX_SIZE = 10000000000;
if (size > MAX_SIZE) {
fail(FileError.QUOTA_EXCEEDED_ERR);
return;
}
var fs;
switch (type) {
case LocalFileSystem.TEMPORARY:
fs = getFS('temporary');
break;
case LocalFileSystem.PERSISTENT:
fs = getFS('persistent');
break;
}
if (fs) { win(fs); } else { fail(FileError.NOT_FOUND_ERR); }
},
resolveLocalFileSystemURI: function (success, fail, args) {
var uri = args[0];
var path = pathFromURL(uri);
var fs = getFilesystemFromURL(uri);
if (!fs || !validName(path)) {
fail(FileError.ENCODING_ERR);
return;
}
if (path.indexOf(fs.winpath) === 0) { path = path.substr(fs.winpath.length); }
var abspath = cordovaPathToNative(fs.winpath + path);
getFileFromPathAsync(abspath).done(
function (storageFile) {
success(new FileEntry(storageFile.name, path, fs.name, fs.makeNativeURL(path)));
}, function () {
getFolderFromPathAsync(abspath).done(
function (storageFolder) {
success(new DirectoryEntry(storageFolder.name, path, fs.name, fs.makeNativeURL(path)));
}, function () {
fail(FileError.NOT_FOUND_ERR);
}
);
}
);
}
};
require('cordova/exec/proxy').add('File', module.exports);