arnaucube
arnaucube/openEventsPlatformAppPublic Self-hosted repository
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);