/* * * 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 (err) { // eslint-disable-line handle-callback-err 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 (err) { // eslint-disable-line handle-callback-err 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 (err) { // eslint-disable-line handle-callback-err 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) { // eslint-disable-line no-undef 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);