diff --git a/README.md b/README.md index 56c737c1d..67584c673 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,6 @@ Although the object is in the global scope, it is not available to applications - Android - iOS -- OS X -- Windows* - Browser \* _These platforms do not support `FileReader.readAsArrayBuffer` nor `FileWriter.write(blob)`._ @@ -70,22 +68,22 @@ Each URL is in the form _file:///path/to/spot/_, and can be converted to a `DirectoryEntry` using `window.resolveLocalFileSystemURL()`. * `cordova.file.applicationDirectory` - Read-only directory where the application - is installed. (_iOS_, _Android_, _BlackBerry 10_, _OSX_, _windows_) + is installed. (_iOS_, _Android_) * `cordova.file.applicationStorageDirectory` - Root directory of the application's - sandbox; on iOS & windows this location is read-only (but specific subdirectories [like - `/Documents` on iOS or `/localState` on windows] are read-write). All data contained within - is private to the app. (_iOS_, _Android_, _BlackBerry 10_, _OSX_) + sandbox; on iOS this location is read-only (but specific subdirectories [like + `/Documents` on iOS] is read-write). All data contained within + is private to the app. (_iOS_, _Android_) * `cordova.file.dataDirectory` - Persistent and private data storage within the application's sandbox using internal memory (on Android, if you need to use external memory, use `.externalDataDirectory`). On iOS, this directory is not - synced with iCloud (use `.syncedDataDirectory`). (_iOS_, _Android_, _BlackBerry 10_, _windows_) + synced with iCloud (use `.syncedDataDirectory`). (_iOS_, _Android_) * `cordova.file.cacheDirectory` - Directory for cached data files or any files that your app can re-create easily. The OS may delete these files when the device runs low on storage, nevertheless, apps should not rely on the OS to delete files - in here. (_iOS_, _Android_, _BlackBerry 10_, _OSX_, _windows_) + in here. (_iOS_, _Android_) * `cordova.file.externalApplicationStorageDirectory` - Application space on external storage. (_Android_). See [Quirks](#androids-external-storage-quirks). @@ -96,19 +94,17 @@ Each URL is in the form _file:///path/to/spot/_, and can be converted to a * `cordova.file.externalCacheDirectory` - Application cache on external storage. (_Android_). See [Quirks](#androids-external-storage-quirks). -* `cordova.file.externalRootDirectory` - External storage (SD card) root. (_Android_, _BlackBerry 10_). See [Quirks](#androids-external-storage-quirks). +* `cordova.file.externalRootDirectory` - External storage (SD card) root. (_Android_). See [Quirks](#androids-external-storage-quirks). * `cordova.file.tempDirectory` - Temp directory that the OS can clear at will. Do not rely on the OS to clear this directory; your app should always remove files as - applicable. (_iOS_, _OSX_, _windows_) + applicable. (_iOS_) * `cordova.file.syncedDataDirectory` - Holds app-specific files that should be synced - (e.g. to iCloud). (_iOS_, _windows_) + (e.g. to iCloud). (_iOS_) * `cordova.file.documentsDirectory` - Files private to the app, but that are meaningful - to other application (e.g. Office files). Note that for _OSX_ this is the user's `~/Documents` directory. (_iOS_, _OSX_) - -* `cordova.file.sharedDirectory` - Files globally available to all applications (_BlackBerry 10_) + to other application (e.g. Office files). (_iOS_) ## File System Layouts @@ -191,41 +187,6 @@ These limitations only applies to external filesystems (e.g. `cordova.file.exter If interfacing with the external file system is a requirement for your application, consider using a [MediaStore](https://www.npmjs.com/search?q=ecosystem%3Acordova%20storage%20access%20framework) plugin instead. -### OS X File System Layout - -| Device Path | `cordova.file.*` | `iosExtraFileSystems` | r/w? | OS clears | private | -|:-------------------------------------------------|:----------------------------|:----------------------|:----:|:---------:|:-------:| -| `/Applications/.app/` | - | bundle | r | N/A | Yes | -|     `Content/Resources/` | applicationDirectory | - | r | N/A | Yes | -| `~/Library/Application Support//` | applicationStorageDirectory | - | r/w | No | Yes | -|     `files/` | dataDirectory | - | r/w | No | Yes | -| `~/Documents/` | documentsDirectory | documents | r/w | No | No | -| `~/Library/Caches//` | cacheDirectory | cache | r/w | No | Yes | -| `/tmp/` | tempDirectory | - | r/w | Yes\* | Yes | -| `/` | rootDirectory | root | r/w | No\*\* | No | - -**Note**: This is the layout for non sandboxed applications. I you enable sandboxing, the `applicationStorageDirectory` will be below ` ~/Library/Containers//Data/Library/Application Support`. - -\* Files persist across app restarts and upgrades, but this directory can - be cleared whenever the OS desires. Your app should be able to recreate any - content that might be deleted. You should clear this directory as - appropriate for your application. - -\*\* Allows access to the entire file system. This is only available for non sandboxed apps. - -### Windows File System Layout - -| Device Path | `cordova.file.*` | r/w? | persistent? | OS clears | private | -|:------------------------------------------------------|:----------------------------|:----:|:-----------:|:---------:|:-------:| -| `ms-appdata:///` | applicationDirectory | r | N/A | N/A | Yes | -|    `local/` | dataDirectory | r/w | Yes | No | Yes | -|    `temp/` | cacheDirectory | r/w | No | Yes\* | Yes | -|    `temp/` | tempDirectory | r/w | No | Yes\* | Yes | -|    `roaming/` | syncedDataDirectory | r/w | Yes | No | Yes | - -\* The OS may periodically clear this directory - - ## Android Quirks ### Android Persistent storage location @@ -510,10 +471,6 @@ var my_media = new Media('cdvfile://localhost/temporary/path/to/file.mp3', ...); my_media.play(); ``` -#### cdvfile quirks -- Using `cdvfile://` paths in the DOM is not supported on Windows platform (a path can be converted to native instead). - - ## List of Error Codes and Meanings When an error is thrown, one of the following codes will be used. @@ -582,7 +539,7 @@ When you get file system access using `requestFileSystem`, access is granted for Here is a request for persistent storage. ->*Note* When targeting WebView clients (instead of a browser) or native apps (Windows), you dont need to use `requestQuota` before using persistent storage. +>*Note* When targeting WebView clients (instead of a browser), you dont need to use `requestQuota` before using persistent storage. ```js window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) { @@ -848,12 +805,6 @@ function displayImageByFileURL(fileEntry) { } ``` -If you are using some platform-specific URIs instead of a FileEntry and you want to display an image, you may need to include the main part of the URI in the Content-Security-Policy element in index.html. For example, on Windows 10, you can include `ms-appdata:` in your element. Here is an example. - -```html - -``` - ## Create Directories In the code here, you create directories in the root of the app storage location. You could use this code with any writable storage location (that is, any DirectoryEntry). Here, you write to the application cache (assuming that you used window.TEMPORARY to get your FileSystem object) by passing fs.root into this function. diff --git a/package.json b/package.json index 8f63f30a0..0de4688c6 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,7 @@ "platforms": [ "android", "browser", - "ios", - "osx", - "windows" + "ios" ] }, "repository": "github:apache/cordova-plugin-file", @@ -21,9 +19,7 @@ "ecosystem:cordova", "cordova-android", "cordova-browser", - "cordova-ios", - "cordova-osx", - "cordova-windows" + "cordova-ios" ], "scripts": { "test": "npm run lint", diff --git a/plugin.xml b/plugin.xml index f99020d80..87fee0b01 100644 --- a/plugin.xml +++ b/plugin.xml @@ -201,46 +201,6 @@ to config.xml in order for the application to find previously stored files. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/browser/FileProxy.js b/src/browser/FileProxy.js index 57d279457..ef2bd1c32 100644 --- a/src/browser/FileProxy.js +++ b/src/browser/FileProxy.js @@ -107,7 +107,7 @@ }, errorCallback); }; - // Overridden by Android, BlackBerry 10 and iOS to populate fsMap + // Overridden by Android and iOS to populate fsMap require('./fileSystems').getFs = function (name, callback) { callback(new FileSystem(name, fs_.root)); }; diff --git a/src/osx/CDVFile.h b/src/osx/CDVFile.h deleted file mode 100644 index 13a9360ea..000000000 --- a/src/osx/CDVFile.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - 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. - */ - -#import -#import - -NSString* const kCDVFilesystemURLPrefix; - -/** -* The default filesystems if non are specified. -*/ -#define CDV_FILESYSTEMS_DEFAULT @"documents,cache,bundle,root" - -/** -* Preference name of the extra filesystems to be "mounted". the following are supported: -* 'bundle' - mounts the application directory -* 'documents' - mounts the users Documents directory (~/Documents) -* 'root' - mounts the root file system -* 'cache' - mounts the caches directory (~/Library/Caches/ *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback; -- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback; -- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback; - -- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url; -- (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir; - -@property (nonatomic,strong) NSString *name; -@property (nonatomic, copy) NSURL*(^urlTransformer)(NSURL*); - -@optional -- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)localURI; -- (CDVFilesystemURL *)URLforFilesystemPath:(NSString *)path; - -@end - -@interface CDVFile : CDVPlugin { - NSString* rootDocsPath; - NSString* appDocsPath; - NSString* appLibraryPath; - NSString* appTempPath; - - NSMutableArray* fileSystems_; - BOOL userHasAllowed; -} - -- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath; -- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystemName:(NSString *)fsName isDirectory:(BOOL)isDir; -- (NSDictionary *)makeEntryForURL:(NSURL *)URL; -- (CDVFilesystemURL *)fileSystemURLforLocalPath:(NSString *)localPath; - -- (NSObject *)filesystemForURL:(CDVFilesystemURL *)localURL; - -/* Native Registration API */ -- (void)registerFilesystem:(NSObject *)fs; -- (NSObject *)fileSystemByName:(NSString *)fsName; - -/* Exec API */ -- (void)requestFileSystem:(CDVInvokedUrlCommand*)command; -- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command; -- (void)getDirectory:(CDVInvokedUrlCommand*)command; -- (void)getFile:(CDVInvokedUrlCommand*)command; -- (void)getParent:(CDVInvokedUrlCommand*)command; -- (void)removeRecursively:(CDVInvokedUrlCommand*)command; -- (void)remove:(CDVInvokedUrlCommand*)command; -- (void)copyTo:(CDVInvokedUrlCommand*)command; -- (void)moveTo:(CDVInvokedUrlCommand*)command; -- (void)getFileMetadata:(CDVInvokedUrlCommand*)command; -- (void)readEntries:(CDVInvokedUrlCommand*)command; -- (void)readAsText:(CDVInvokedUrlCommand*)command; -- (void)readAsDataURL:(CDVInvokedUrlCommand*)command; -- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command; -- (void)write:(CDVInvokedUrlCommand*)command; -- (void)testFileExists:(CDVInvokedUrlCommand*)command; -- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command; -- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command; -- (void)truncate:(CDVInvokedUrlCommand*)command; -- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy; - -/* Compatibilty with older File API */ -- (NSString*)getMimeTypeFromPath:(NSString*)fullPath; -- (NSDictionary *)getDirectoryEntry:(NSString *)target isDirectory:(BOOL)bDirRequest; - -/* Conversion between filesystem paths and URLs */ -- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)URL; - -/* Internal methods for testing */ -- (void)_getLocalFilesystemPath:(CDVInvokedUrlCommand*)command; - -/** - * local path of the 'documents' file system (~/Documents) - */ -@property (nonatomic, strong) NSString* appDocsPath; - -/** -* local path of the 'applicationStorageDirectory' file system (~/Library/Application Support/) -*/ -@property (nonatomic, strong) NSString* appSupportPath; - -/** -* local path of the 'persistent' file system (~/Library/Application Support//files) -*/ -@property (nonatomic, strong) NSString* appDataPath; - -/** -* local path of the 'documents' file system (~/Documents) -*/ -@property (nonatomic, strong) NSString* appTempPath; - -/** -* local path of the 'cache' file system (~/Library/Caches/) -*/ -@property (nonatomic, strong) NSString* appCachePath; - -/** - * registered file systems - */ -@property (nonatomic, strong) NSMutableArray* fileSystems; - -@property BOOL userHasAllowed; - -@end diff --git a/src/osx/CDVFile.m b/src/osx/CDVFile.m deleted file mode 100644 index 75a600195..000000000 --- a/src/osx/CDVFile.m +++ /dev/null @@ -1,1056 +0,0 @@ -/* - 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. - */ - -#import "CDVFile.h" -#import "CDVLocalFilesystem.h" -#import - -static NSString* toBase64(NSData* data) { - SEL s1 = NSSelectorFromString(@"cdv_base64EncodedString"); - SEL s2 = NSSelectorFromString(@"base64EncodedString"); - SEL s3 = NSSelectorFromString(@"base64EncodedStringWithOptions:"); - - if ([data respondsToSelector:s1]) { - NSString* (*func)(id, SEL) = (void *)[data methodForSelector:s1]; - return func(data, s1); - } else if ([data respondsToSelector:s2]) { - NSString* (*func)(id, SEL) = (void *)[data methodForSelector:s2]; - return func(data, s2); - } else if ([data respondsToSelector:s3]) { - NSString* (*func)(id, SEL, NSUInteger) = (void *)[data methodForSelector:s3]; - return func(data, s3, 0); - } else { - return nil; - } -} - -CDVFile *filePlugin = nil; - -extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import)); - -#ifndef __IPHONE_5_1 - NSString* const NSURLIsExcludedFromBackupKey = @"NSURLIsExcludedFromBackupKey"; -#endif - -NSString* const kCDVFilesystemURLPrefix = @"cdvfile"; - -@implementation CDVFilesystemURL -@synthesize url=_url; -@synthesize fileSystemName=_fileSystemName; -@synthesize fullPath=_fullPath; - -- (id) initWithString:(NSString *)strURL -{ - if ( self = [super init] ) { - NSURL *decodedURL = [NSURL URLWithString:strURL]; - return [self initWithURL:decodedURL]; - } - return nil; -} - --(id) initWithURL:(NSURL *)URL -{ - if ( self = [super init] ) { - _url = URL; - _fileSystemName = [self filesystemNameForLocalURI:URL]; - _fullPath = [self fullPathForLocalURI:URL]; - } - return self; -} - -/* - * IN - * NSString localURI - * OUT - * NSString FileSystem Name for this URI, or nil if it is not recognized. - */ -- (NSString *)filesystemNameForLocalURI:(NSURL *)uri -{ - if ([[uri scheme] isEqualToString:kCDVFilesystemURLPrefix] && [[uri host] isEqualToString:@"localhost"]) { - NSArray *pathComponents = [uri pathComponents]; - if (pathComponents != nil && pathComponents.count > 1) { - return [pathComponents objectAtIndex:1]; - } - } - return nil; -} - -/* - * IN - * NSString localURI - * OUT - * NSString fullPath component suitable for an Entry object. - * The incoming URI should be properly escaped. The returned fullPath is unescaped. - */ -- (NSString *)fullPathForLocalURI:(NSURL *)uri -{ - if ([[uri scheme] isEqualToString:kCDVFilesystemURLPrefix] && [[uri host] isEqualToString:@"localhost"]) { - NSString *path = [uri path]; - if ([uri query]) { - path = [NSString stringWithFormat:@"%@?%@", path, [uri query]]; - } - NSRange slashRange = [path rangeOfString:@"/" options:0 range:NSMakeRange(1, path.length-1)]; - if (slashRange.location == NSNotFound) { - return @""; - } - return [path substringFromIndex:slashRange.location]; - } - return nil; -} - -+ (CDVFilesystemURL *)fileSystemURLWithString:(NSString *)strURL -{ - return [[CDVFilesystemURL alloc] initWithString:strURL]; -} - -+ (CDVFilesystemURL *)fileSystemURLWithURL:(NSURL *)URL -{ - return [[CDVFilesystemURL alloc] initWithURL:URL]; -} - -- (NSString *)absoluteURL -{ - return [NSString stringWithFormat:@"cdvfile://localhost/%@%@", self.fileSystemName, self.fullPath]; -} - -@end - -@implementation CDVFilesystemURLProtocol - -+ (BOOL)canInitWithRequest:(NSURLRequest*)request -{ - NSURL* url = [request URL]; - return [[url scheme] isEqualToString:kCDVFilesystemURLPrefix]; -} - -+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)request -{ - return request; -} - -+ (BOOL)requestIsCacheEquivalent:(NSURLRequest*)requestA toRequest:(NSURLRequest*)requestB -{ - return [[[requestA URL] resourceSpecifier] isEqualToString:[[requestB URL] resourceSpecifier]]; -} - -- (void)startLoading -{ - CDVFilesystemURL* url = [CDVFilesystemURL fileSystemURLWithURL:[[self request] URL]]; - NSObject *fs = [filePlugin filesystemForURL:url]; - [fs readFileAtURL:url start:0 end:-1 callback:^void(NSData *data, NSString *mimetype, CDVFileError error) { - NSMutableDictionary* responseHeaders = [[NSMutableDictionary alloc] init]; - responseHeaders[@"Cache-Control"] = @"no-cache"; - - if (!error) { - responseHeaders[@"Content-Type"] = mimetype; - NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url.url statusCode:200 HTTPVersion:@"HTTP/1.1"headerFields:responseHeaders]; - [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; - [[self client] URLProtocol:self didLoadData:data]; - [[self client] URLProtocolDidFinishLoading:self]; - } else { - NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url.url statusCode:404 HTTPVersion:@"HTTP/1.1"headerFields:responseHeaders]; - [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; - [[self client] URLProtocolDidFinishLoading:self]; - } - }]; -} - -- (void)stopLoading -{} - -- (NSCachedURLResponse *)connection:(NSURLConnection *)connection - willCacheResponse:(NSCachedURLResponse*)cachedResponse { - return nil; -} - -@end - - -@implementation CDVFile - -@synthesize appDocsPath, appDataPath, appSupportPath, appTempPath, appCachePath, userHasAllowed, fileSystems=fileSystems_; - -- (void)registerFilesystem:(NSObject *)fs { - __weak CDVFile* weakSelf = self; - SEL sel = NSSelectorFromString(@"urlTransformer"); - // for backwards compatibility - we check if this property is there - // we create a wrapper block because the urlTransformer property - // on the commandDelegate might be set dynamically at a future time - // (and not dependent on plugin loading order) - if ([self.commandDelegate respondsToSelector:sel]) { - fs.urlTransformer = ^NSURL*(NSURL* urlToTransform) { - // grab the block from the commandDelegate - NSURL* (^urlTransformer)(NSURL*) = ((id(*)(id, SEL))objc_msgSend)(weakSelf.commandDelegate, sel); - // if block is not null, we call it - if (urlTransformer) { - return urlTransformer(urlToTransform); - } else { // else we return the same url - return urlToTransform; - } - }; - } - [fileSystems_ addObject:fs]; -} - -- (NSObject *)fileSystemByName:(NSString *)fsName -{ - if (self.fileSystems != nil) { - for (NSObject *fs in self.fileSystems) { - if ([fs.name isEqualToString:fsName]) { - return fs; - } - } - } - return nil; - -} - -- (NSObject *)filesystemForURL:(CDVFilesystemURL *)localURL { - if (localURL.fileSystemName == nil) return nil; - @try { - return [self fileSystemByName:localURL.fileSystemName]; - } - @catch (NSException *e) { - return nil; - } -} - -- (NSArray *)getExtraFileSystemsPreference:(NSWindowController *)vc -{ - NSString *filesystemsStr = nil; - if([self.viewController isKindOfClass:[CDVViewController class]]) { - CDVViewController *vc = self.viewController; - NSDictionary *settings = [vc settings]; - filesystemsStr = [settings[CDV_PREF_EXTRA_FILESYSTEM] lowercaseString]; - } - if (!filesystemsStr) { - filesystemsStr = CDV_FILESYSTEMS_DEFAULT; - } - return [filesystemsStr componentsSeparatedByString:@","]; -} - -- (void)makeNonSyncable:(NSString*)path { - [[NSFileManager defaultManager] createDirectoryAtPath:path - withIntermediateDirectories:YES - attributes:nil - error:nil]; - NSURL* url = [NSURL fileURLWithPath:path]; - [url setResourceValue: [NSNumber numberWithBool: YES] - forKey: NSURLIsExcludedFromBackupKey error:nil]; - -} - -- (void)registerExtraFileSystems:(NSArray *)filesystems fromAvailableSet:(NSDictionary *)availableFileSystems -{ - NSMutableSet *installedFilesystems = [[NSMutableSet alloc] initWithCapacity:7]; - - /* Register filesystems in order */ - for (NSString *fsName in filesystems) { - if (![installedFilesystems containsObject:fsName]) { - NSString *fsRoot = availableFileSystems[fsName]; - if (fsRoot) { - [filePlugin registerFilesystem:[[CDVLocalFilesystem alloc] initWithName:fsName root:fsRoot]]; - [installedFilesystems addObject:fsName]; - } else { - NSLog(@"Unrecognized extra filesystem identifier: %@", fsName); - } - } - } -} - -- (NSDictionary *)getAvailableFileSystems -{ - return @{ - @"documents": self.appDocsPath, - @"cache": self.appCachePath, - @"bundle": [[NSBundle mainBundle] bundlePath], - @"root": @"/" - }; -} - -- (void)pluginInitialize -{ filePlugin = self; - [NSURLProtocol registerClass:[CDVFilesystemURLProtocol class]]; - - fileSystems_ = [[NSMutableArray alloc] initWithCapacity:3]; - - // Get the Temporary directory path - self.appTempPath = [NSTemporaryDirectory()stringByStandardizingPath]; // remove trailing slash from NSTemporaryDirectory() - [self registerFilesystem:[[CDVLocalFilesystem alloc] initWithName:@"temporary" root:self.appTempPath]]; - - // ~/Library/Application Support/ - self.appSupportPath = [self getSupportDirectoryFor:NSApplicationSupportDirectory pathComponents:nil]; - - // ~/Library/Application Support//files - self.appDataPath = [self getSupportDirectoryFor:NSApplicationSupportDirectory pathComponents:@[@"files"]]; - [self registerFilesystem:[[CDVLocalFilesystem alloc] initWithName:@"persistent" root:self.appDataPath]]; - - // ~/Documents/ - self.appDocsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; - - // ~/Library/Caches//files - self.appCachePath = [self getSupportDirectoryFor:NSCachesDirectory pathComponents:nil]; - - [self registerExtraFileSystems:[self getExtraFileSystemsPreference:self.viewController] - fromAvailableSet:[self getAvailableFileSystems]]; -} - -- (NSString*) getSupportDirectoryFor: (NSSearchPathDirectory) directory pathComponents: (NSArray*) components { - NSError* error; - NSFileManager* fm = [NSFileManager defaultManager]; - NSURL* supportDir = [fm URLForDirectory:directory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error]; - if (supportDir == nil) { - NSLog(@"unable to get support directory: %@", error); - return nil; - } - - NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier]; - NSURL *dirPath = [supportDir URLByAppendingPathComponent:bundleID]; - for (NSString* pathComponent in components) { - dirPath = [dirPath URLByAppendingPathComponent:pathComponent]; - } - - if (![fm fileExistsAtPath:dirPath.path]) { - if (![fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES attributes:nil error:&error]) { - NSLog(@"unable to create support directory: %@", error); - return nil; - } - } - return dirPath.path; -} - - -- (CDVFilesystemURL *)fileSystemURLforArg:(NSString *)urlArg -{ - CDVFilesystemURL* ret = nil; - if ([urlArg hasPrefix:@"file://"]) { - /* This looks like a file url. Get the path, and see if any handlers recognize it. */ - NSURL *fileURL = [NSURL URLWithString:urlArg]; - NSURL *resolvedFileURL = [fileURL URLByResolvingSymlinksInPath]; - NSString *path = [resolvedFileURL path]; - ret = [self fileSystemURLforLocalPath:path]; - } else { - ret = [CDVFilesystemURL fileSystemURLWithString:urlArg]; - } - return ret; -} - -- (CDVFilesystemURL *)fileSystemURLforLocalPath:(NSString *)localPath -{ - CDVFilesystemURL *localURL = nil; - NSUInteger shortestFullPath = 0; - - // Try all installed filesystems, in order. Return the most match url. - for (id object in self.fileSystems) { - if ([object respondsToSelector:@selector(URLforFilesystemPath:)]) { - CDVFilesystemURL *url = [object URLforFilesystemPath:localPath]; - if (url){ - // A shorter fullPath would imply that the filesystem is a better match for the local path - if (!localURL || ([[url fullPath] length] < shortestFullPath)) { - localURL = url; - shortestFullPath = [[url fullPath] length]; - } - } - } - } - return localURL; -} - -- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath -{ - NSFileManager* fMgr = [[NSFileManager alloc] init]; - - NSError* __autoreleasing pError = nil; - - NSDictionary* pDict = [fMgr attributesOfFileSystemForPath:appPath error:&pError]; - NSNumber* pNumAvail = (NSNumber*)[pDict objectForKey:NSFileSystemFreeSize]; - - return pNumAvail; -} - -/* Request the File System info - * - * IN: - * arguments[0] - type (number as string) - * TEMPORARY = 0, PERSISTENT = 1; - * arguments[1] - size - * - * OUT: - * Dictionary representing FileSystem object - * name - the human readable directory name - * root = DirectoryEntry object - * bool isDirectory - * bool isFile - * string name - * string fullPath - * fileSystem = FileSystem object - !! ignored because creates circular reference !! - */ - -- (void)requestFileSystem:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* strType = [command argumentAtIndex:0]; - unsigned long long size = [[command argumentAtIndex:1] longLongValue]; - - int type = [strType intValue]; - CDVPluginResult* result = nil; - - if (type > self.fileSystems.count) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:NOT_FOUND_ERR]; - NSLog(@"No filesystem of type requested"); - } else { - NSString* fullPath = @"/"; - // check for avail space for size request - NSNumber* pNumAvail = [self checkFreeDiskSpace:self.appSupportPath]; - // NSLog(@"Free space: %@", [NSString stringWithFormat:@"%qu", [ pNumAvail unsignedLongLongValue ]]); - if (pNumAvail && ([pNumAvail unsignedLongLongValue] < size)) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:QUOTA_EXCEEDED_ERR]; - } else { - NSObject *rootFs = [self.fileSystems objectAtIndex:type]; - if (rootFs == nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:NOT_FOUND_ERR]; - NSLog(@"No filesystem of type requested"); - } else { - NSMutableDictionary* fileSystem = [NSMutableDictionary dictionaryWithCapacity:2]; - [fileSystem setObject:rootFs.name forKey:@"name"]; - NSDictionary* dirEntry = [self makeEntryForPath:fullPath fileSystemName:rootFs.name isDirectory:YES]; - [fileSystem setObject:dirEntry forKey:@"root"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem]; - } - } - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - - -- (void)requestAllFileSystems:(CDVInvokedUrlCommand*)command -{ - NSMutableArray* ret = [[NSMutableArray alloc] init]; - for (NSObject* root in fileSystems_) { - [ret addObject:[self makeEntryForPath:@"/" fileSystemName:root.name isDirectory:YES]]; - } - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:ret]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (void)requestAllPaths:(CDVInvokedUrlCommand*)command -{ - NSDictionary* ret = @{ - @"applicationDirectory": [[NSURL fileURLWithPath:[[NSBundle mainBundle] resourcePath]] absoluteString], - @"applicationStorageDirectory": [[NSURL fileURLWithPath:self.appSupportPath] absoluteString], - @"dataDirectory": [[NSURL fileURLWithPath:self.appDataPath] absoluteString], - @"documentsDirectory": [[NSURL fileURLWithPath:self.appDocsPath] absoluteString], - @"cacheDirectory": [[NSURL fileURLWithPath:self.appCachePath] absoluteString], - @"tempDirectory":[[NSURL fileURLWithPath:self.appTempPath] absoluteString], - @"rootDirectory": @"file:///", - }; - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:ret]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* Creates and returns a dictionary representing an Entry Object - * - * IN: - * NSString* fullPath of the entry - * int fsType - FileSystem type - * BOOL isDirectory - YES if this is a directory, NO if is a file - * OUT: - * NSDictionary* Entry object - * bool as NSNumber isDirectory - * bool as NSNumber isFile - * NSString* name - last part of path - * NSString* fullPath - * NSString* filesystemName - FileSystem name -- actual filesystem will be created on the JS side if necessary, to avoid - * creating circular reference (FileSystem contains DirectoryEntry which contains FileSystem.....!!) - */ -- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystemName:(NSString *)fsName isDirectory:(BOOL)isDir -{ - NSObject *fs = [self fileSystemByName:fsName]; - return [fs makeEntryForPath:fullPath isDirectory:isDir]; -} - -- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)localURL -{ - NSObject *fs = [self filesystemForURL:localURL]; - return [fs makeEntryForLocalURL:localURL]; -} - -- (NSDictionary *)makeEntryForURL:(NSURL *)URL -{ - CDVFilesystemURL* fsURL = [self fileSystemURLforArg:[URL absoluteString]]; - return [self makeEntryForLocalURL:fsURL]; -} - -/* - * Given a URI determine the File System information associated with it and return an appropriate W3C entry object - * IN - * NSString* localURI: Should be an escaped local filesystem URI - * OUT - * Entry object - * bool isDirectory - * bool isFile - * string name - * string fullPath - * fileSystem = FileSystem object - !! ignored because creates circular reference FileSystem contains DirectoryEntry which contains FileSystem.....!! - */ -- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* localURIstr = [command argumentAtIndex:0]; - CDVPluginResult* result; - - localURIstr = [self encodePath:localURIstr]; //encode path before resolving - CDVFilesystemURL* inputURI = [self fileSystemURLforArg:localURIstr]; - - if (inputURI == nil || inputURI.fileSystemName == nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR]; - } else { - NSObject *fs = [self filesystemForURL:inputURI]; - if (fs == nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR]; - } else { - result = [fs entryForLocalURI:inputURI]; - } - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -//encode path with percent escapes --(NSString *)encodePath:(NSString *)path -{ - NSString *decodedPath = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //decode incase it's already encoded to avoid encoding twice - return [decodedPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; -} - - -/* Part of DirectoryEntry interface, creates or returns the specified directory - * IN: - * NSString* localURI - local filesystem URI for this directory - * NSString* path - directory to be created/returned; may be full path or relative path - * NSDictionary* - Flags object - * boolean as NSNumber create - - * if create is true and directory does not exist, create dir and return directory entry - * if create is true and exclusive is true and directory does exist, return error - * if create is false and directory does not exist, return error - * if create is false and the path represents a file, return error - * boolean as NSNumber exclusive - used in conjunction with create - * if exclusive is true and create is true - specifies failure if directory already exists - * - * - */ -- (void)getDirectory:(CDVInvokedUrlCommand*)command -{ - NSMutableArray* arguments = [NSMutableArray arrayWithArray:command.arguments]; - NSMutableDictionary* options = nil; - - if ([arguments count] >= 3) { - options = [command argumentAtIndex:2 withDefault:nil]; - } - // add getDir to options and call getFile() - if (options != nil) { - options = [NSMutableDictionary dictionaryWithDictionary:options]; - } else { - options = [NSMutableDictionary dictionaryWithCapacity:1]; - } - [options setObject:[NSNumber numberWithInt:1] forKey:@"getDir"]; - if ([arguments count] >= 3) { - [arguments replaceObjectAtIndex:2 withObject:options]; - } else { - [arguments addObject:options]; - } - CDVInvokedUrlCommand* subCommand = - [[CDVInvokedUrlCommand alloc] initWithArguments:arguments - callbackId:command.callbackId - className:command.className - methodName:command.methodName]; - - [self getFile:subCommand]; -} - -/* Part of DirectoryEntry interface, creates or returns the specified file - * IN: - * NSString* baseURI - local filesytem URI for the base directory to search - * NSString* requestedPath - file to be created/returned; may be absolute path or relative path - * NSDictionary* options - Flags object - * boolean as NSNumber create - - * if create is true and file does not exist, create file and return File entry - * if create is true and exclusive is true and file does exist, return error - * if create is false and file does not exist, return error - * if create is false and the path represents a directory, return error - * boolean as NSNumber exclusive - used in conjunction with create - * if exclusive is true and create is true - specifies failure if file already exists - */ -- (void)getFile:(CDVInvokedUrlCommand*)command -{ - NSString* baseURIstr = [command argumentAtIndex:0]; - CDVFilesystemURL* baseURI = [self fileSystemURLforArg:baseURIstr]; - NSString* requestedPath = [command argumentAtIndex:1]; - NSDictionary* options = [command argumentAtIndex:2 withDefault:nil]; - - NSObject *fs = [self filesystemForURL:baseURI]; - CDVPluginResult* result = [fs getFileForURL:baseURI requestedPath:requestedPath options:options]; - - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* - * Look up the parent Entry containing this Entry. - * If this Entry is the root of its filesystem, its parent is itself. - * IN: - * NSArray* arguments - * 0 - NSString* localURI - * NSMutableDictionary* options - * empty - */ -- (void)getParent:(CDVInvokedUrlCommand*)command -{ - // arguments are URL encoded - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - - NSObject *fs = [self filesystemForURL:localURI]; - CDVPluginResult* result = [fs getParentForURL:localURI]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* - * set MetaData of entry - * Currently we only support "com.apple.MobileBackup" (boolean) - */ -- (void)setMetadata:(CDVInvokedUrlCommand*)command -{ - // arguments - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - NSDictionary* options = [command argumentAtIndex:1 withDefault:nil]; - NSObject *fs = [self filesystemForURL:localURI]; - CDVPluginResult* result = [fs setMetadataForURL:localURI withObject:options]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* removes the directory or file entry - * IN: - * NSArray* arguments - * 0 - NSString* localURI - * - * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir - * returns INVALID_MODIFICATION_ERR if is non-empty dir or asset library file - * returns NOT_FOUND_ERR if file or dir is not found -*/ -- (void)remove:(CDVInvokedUrlCommand*)command -{ - // arguments - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - CDVPluginResult* result = nil; - - if ([localURI.fullPath isEqualToString:@""]) { - // error if try to remove top level (documents or tmp) dir - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; - } else { - NSObject *fs = [self filesystemForURL:localURI]; - result = [fs removeFileAtURL:localURI]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* recursively removes the directory - * IN: - * NSArray* arguments - * 0 - NSString* localURI - * - * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir - * returns NOT_FOUND_ERR if file or dir is not found - */ -- (void)removeRecursively:(CDVInvokedUrlCommand*)command -{ - // arguments - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - CDVPluginResult* result = nil; - - if ([localURI.fullPath isEqualToString:@""]) { - // error if try to remove top level (documents or tmp) dir - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; - } else { - NSObject *fs = [self filesystemForURL:localURI]; - result = [fs recursiveRemoveFileAtURL:localURI]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (void)copyTo:(CDVInvokedUrlCommand*)command -{ - [self doCopyMove:command isCopy:YES]; -} - -- (void)moveTo:(CDVInvokedUrlCommand*)command -{ - [self doCopyMove:command isCopy:NO]; -} - -/* Copy/move a file or directory to a new location - * IN: - * NSArray* arguments - * 0 - NSString* URL of entry to copy - * 1 - NSString* URL of the directory into which to copy/move the entry - * 2 - Optionally, the new name of the entry, defaults to the current name - * BOOL - bCopy YES if copy, NO if move - */ -- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy -{ - NSArray* arguments = command.arguments; - - // arguments - NSString* srcURLstr = [command argumentAtIndex:0]; - NSString* destURLstr = [command argumentAtIndex:1]; - - CDVPluginResult *result; - - if (!srcURLstr || !destURLstr) { - // either no source or no destination provided - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVFilesystemURL* srcURL = [self fileSystemURLforArg:srcURLstr]; - CDVFilesystemURL* destURL = [self fileSystemURLforArg:destURLstr]; - - NSObject *srcFs = [self filesystemForURL:srcURL]; - NSObject *destFs = [self filesystemForURL:destURL]; - - // optional argument; use last component from srcFullPath if new name not provided - NSString* newName = ([arguments count] > 2) ? [command argumentAtIndex:2] : [srcURL.url lastPathComponent]; - if ([newName rangeOfString:@":"].location != NSNotFound) { - // invalid chars in new name - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - [destFs copyFileToURL:destURL withName:newName fromFileSystem:srcFs atURL:srcURL copy:bCopy callback:^(CDVPluginResult* result) { - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; - -} - -- (void)getFileMetadata:(CDVInvokedUrlCommand*)command -{ - // arguments - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - NSObject *fs = [self filesystemForURL:localURI]; - - [fs getFileMetadataForURL:localURI callback:^(CDVPluginResult* result) { - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; -} - -- (void)readEntries:(CDVInvokedUrlCommand*)command -{ - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - NSObject *fs = [self filesystemForURL:localURI]; - CDVPluginResult *result = [fs readEntriesAtURL:localURI]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* read and return file data - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * 1 - NSString* encoding - * 2 - NSString* start - * 3 - NSString* end - */ -- (void)readAsText:(CDVInvokedUrlCommand*)command -{ - // arguments - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - NSString* encoding = [command argumentAtIndex:1]; - NSInteger start = [[command argumentAtIndex:2] integerValue]; - NSInteger end = [[command argumentAtIndex:3] integerValue]; - - NSObject *fs = [self filesystemForURL:localURI]; - - if (fs == nil) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - // TODO: implement - if ([@"UTF-8" caseInsensitiveCompare : encoding] != NSOrderedSame) { - NSLog(@"Only UTF-8 encodings are currently supported by readAsText"); - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - [self.commandDelegate runInBackground:^ { - [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - NSString* str = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSUTF8StringEncoding freeWhenDone:NO]; - // Check that UTF8 conversion did not fail. - if (str != nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:str]; - result.associatedObject = data; - } else { - errorCode = ENCODING_ERR; - } - } - if (result == nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; - }]; -} - -/* Read content of text file and return as base64 encoded data url. - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * 1 - NSString* start - * 2 - NSString* end - * - * Determines the mime type from the file extension, returns ENCODING_ERR if mimetype can not be determined. - */ - -- (void)readAsDataURL:(CDVInvokedUrlCommand*)command -{ - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - NSInteger start = [[command argumentAtIndex:1] integerValue]; - NSInteger end = [[command argumentAtIndex:2] integerValue]; - - NSObject *fs = [self filesystemForURL:localURI]; - - [self.commandDelegate runInBackground:^ { - [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - NSString* b64Str = toBase64(data); - NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, b64Str]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; - }]; -} - -/* Read content of text file and return as an arraybuffer - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * 1 - NSString* start - * 2 - NSString* end - */ - -- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command -{ - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - NSInteger start = [[command argumentAtIndex:1] integerValue]; - NSInteger end = [[command argumentAtIndex:2] integerValue]; - - NSObject *fs = [self filesystemForURL:localURI]; - - [self.commandDelegate runInBackground:^ { - [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; - }]; -} - -- (void)readAsBinaryString:(CDVInvokedUrlCommand*)command -{ - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - NSInteger start = [[command argumentAtIndex:1] integerValue]; - NSInteger end = [[command argumentAtIndex:2] integerValue]; - - NSObject *fs = [self filesystemForURL:localURI]; - - [self.commandDelegate runInBackground:^ { - [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - NSString* payload = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSASCIIStringEncoding freeWhenDone:NO]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload]; - result.associatedObject = data; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; - }]; -} - - -- (void)truncate:(CDVInvokedUrlCommand*)command -{ - // arguments - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - unsigned long long pos = (unsigned long long)[[command argumentAtIndex:1] longLongValue]; - - NSObject *fs = [self filesystemForURL:localURI]; - CDVPluginResult *result = [fs truncateFileAtURL:localURI atPosition:pos]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* write - * IN: - * NSArray* arguments - * 0 - NSString* localURI of file to write to - * 1 - NSString* or NSData* data to write - * 2 - NSNumber* position to begin writing - */ -- (void)write:(CDVInvokedUrlCommand*)command -{ - [self.commandDelegate runInBackground:^ { - NSString* callbackId = command.callbackId; - - // arguments - CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; - id argData = [command argumentAtIndex:1]; - unsigned long long pos = (unsigned long long)[[command argumentAtIndex:2] longLongValue]; - - NSObject *fs = [self filesystemForURL:localURI]; - - - [fs truncateFileAtURL:localURI atPosition:pos]; - CDVPluginResult *result; - if ([argData isKindOfClass:[NSString class]]) { - NSData *encData = [argData dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; - result = [fs writeToFileAtURL:localURI withData:encData append:YES]; - } else if ([argData isKindOfClass:[NSData class]]) { - result = [fs writeToFileAtURL:localURI withData:argData append:YES]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Invalid parameter type"]; - } - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - }]; -} - -#pragma mark Methods for converting between URLs and paths - -- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)localURL -{ - for (NSObject *fs in self.fileSystems) { - if ([fs.name isEqualToString:localURL.fileSystemName]) { - if ([fs respondsToSelector:@selector(filesystemPathForURL:)]) { - return [fs filesystemPathForURL:localURL]; - } - } - } - return nil; -} - -#pragma mark Undocumented Filesystem API - -- (void)testFileExists:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command argumentAtIndex:0]; - - // Get the file manager - NSFileManager* fMgr = [NSFileManager defaultManager]; - NSString* appFile = argPath; // [ self getFullPath: argPath]; - - BOOL bExists = [fMgr fileExistsAtPath:appFile]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1 : 0)]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command argumentAtIndex:0]; - - // Get the file manager - NSFileManager* fMgr = [[NSFileManager alloc] init]; - NSString* appFile = argPath; // [self getFullPath: argPath]; - BOOL bIsDir = NO; - BOOL bExists = [fMgr fileExistsAtPath:appFile isDirectory:&bIsDir]; - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1 : 0)]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -// Returns number of bytes available via callback -- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command -{ - // no arguments - - NSNumber* pNumAvail = [self checkFreeDiskSpace:self.appDocsPath]; - - NSString* strFreeSpace = [NSString stringWithFormat:@"%qu", [pNumAvail unsignedLongLongValue]]; - // NSLog(@"Free space is %@", strFreeSpace ); - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:strFreeSpace]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -#pragma mark Compatibility with older File API - -- (NSString*)getMimeTypeFromPath:(NSString*)fullPath -{ - return [CDVLocalFilesystem getMimeTypeFromPath:fullPath]; -} - -- (NSDictionary *)getDirectoryEntry:(NSString *)localPath isDirectory:(BOOL)bDirRequest -{ - CDVFilesystemURL *localURL = [self fileSystemURLforLocalPath:localPath]; - return [self makeEntryForPath:localURL.fullPath fileSystemName:localURL.fileSystemName isDirectory:bDirRequest]; -} - -#pragma mark Internal methods for testing -// Internal methods for testing: Get the on-disk location of a local filesystem url. -// [Currently used for testing file-transfer] - -- (void)_getLocalFilesystemPath:(CDVInvokedUrlCommand*)command -{ - CDVFilesystemURL* localURL = [self fileSystemURLforArg:command.arguments[0]]; - - NSString* fsPath = [self filesystemPathForURL:localURL]; - CDVPluginResult* result; - if (fsPath) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:fsPath]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Cannot resolve URL to a file"]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -@end diff --git a/src/osx/CDVLocalFilesystem.h b/src/osx/CDVLocalFilesystem.h deleted file mode 100644 index a0186c853..000000000 --- a/src/osx/CDVLocalFilesystem.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - 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. - */ - -#import "CDVFile.h" - -@interface CDVLocalFilesystem : NSObject { - NSString *_name; - NSString *_fsRoot; -} - -- (id) initWithName:(NSString *)name root:(NSString *)fsRoot; -+ (NSString*)getMimeTypeFromPath:(NSString*)fullPath; - -@property (nonatomic,strong) NSString *fsRoot; - -@end diff --git a/src/osx/CDVLocalFilesystem.m b/src/osx/CDVLocalFilesystem.m deleted file mode 100644 index 016e39994..000000000 --- a/src/osx/CDVLocalFilesystem.m +++ /dev/null @@ -1,733 +0,0 @@ -/* - 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. - */ - -#import "CDVFile.h" -#import "CDVLocalFilesystem.h" -#import - -@implementation CDVLocalFilesystem -@synthesize name=_name, fsRoot=_fsRoot, urlTransformer; - -- (id) initWithName:(NSString *)name root:(NSString *)fsRoot -{ - if (self) { - _name = name; - _fsRoot = fsRoot; - } - return self; -} - -/* - * IN - * NSString localURI - * OUT - * CDVPluginResult result containing a file or directoryEntry for the localURI, or an error if the - * URI represents a non-existent path, or is unrecognized or otherwise malformed. - */ -- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url -{ - CDVPluginResult* result = nil; - NSDictionary* entry = [self makeEntryForLocalURL:url]; - if (entry) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:entry]; - } else { - // return NOT_FOUND_ERR - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } - return result; -} -- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url { - NSString *path = [self filesystemPathForURL:url]; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL isDir = NO; - // see if exists and is file or dir - BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory:&isDir]; - if (bExists) { - return [self makeEntryForPath:url.fullPath isDirectory:isDir]; - } else { - return nil; - } -} -- (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir -{ - NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5]; - NSString* lastPart = [[self stripQueryParametersFromPath:fullPath] lastPathComponent]; - if (isDir && ![fullPath hasSuffix:@"/"]) { - fullPath = [fullPath stringByAppendingString:@"/"]; - } - [dirEntry setObject:[NSNumber numberWithBool:!isDir] forKey:@"isFile"]; - [dirEntry setObject:[NSNumber numberWithBool:isDir] forKey:@"isDirectory"]; - [dirEntry setObject:fullPath forKey:@"fullPath"]; - [dirEntry setObject:lastPart forKey:@"name"]; - [dirEntry setObject:self.name forKey: @"filesystemName"]; - - NSURL* nativeURL = [NSURL fileURLWithPath:[self filesystemPathForFullPath:fullPath]]; - if (self.urlTransformer) { - nativeURL = self.urlTransformer(nativeURL); - } - - dirEntry[@"nativeURL"] = [nativeURL absoluteString]; - - return dirEntry; -} - -- (NSString *)stripQueryParametersFromPath:(NSString *)fullPath -{ - NSRange questionMark = [fullPath rangeOfString:@"?"]; - if (questionMark.location != NSNotFound) { - return [fullPath substringWithRange:NSMakeRange(0,questionMark.location)]; - } - return fullPath; -} - -- (NSString *)filesystemPathForFullPath:(NSString *)fullPath -{ - NSString *path = nil; - NSString *strippedFullPath = [self stripQueryParametersFromPath:fullPath]; - path = [NSString stringWithFormat:@"%@%@", self.fsRoot, strippedFullPath]; - if ([path length] > 1 && [path hasSuffix:@"/"]) { - path = [path substringToIndex:([path length]-1)]; - } - return path; -} -/* - * IN - * NSString localURI - * OUT - * NSString full local filesystem path for the represented file or directory, or nil if no such path is possible - * The file or directory does not necessarily have to exist. nil is returned if the filesystem type is not recognized, - * or if the URL is malformed. - * The incoming URI should be properly escaped (no raw spaces, etc. URI percent-encoding is expected). - */ -- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)url -{ - return [self filesystemPathForFullPath:url.fullPath]; -} - -- (CDVFilesystemURL *)URLforFullPath:(NSString *)fullPath -{ - if (fullPath) { - NSString* escapedPath = [fullPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - if ([fullPath hasPrefix:@"/"]) { - return [CDVFilesystemURL fileSystemURLWithString:[NSString stringWithFormat:@"%@://localhost/%@%@", kCDVFilesystemURLPrefix, self.name, escapedPath]]; - } - return [CDVFilesystemURL fileSystemURLWithString:[NSString stringWithFormat:@"%@://localhost/%@/%@", kCDVFilesystemURLPrefix, self.name, escapedPath]]; - } - return nil; -} - -- (CDVFilesystemURL *)URLforFilesystemPath:(NSString *)path -{ - return [self URLforFullPath:[self fullPathForFileSystemPath:path]]; - -} - -- (NSString *)normalizePath:(NSString *)rawPath -{ - // If this is an absolute path, the first path component will be '/'. Skip it if that's the case - BOOL isAbsolutePath = [rawPath hasPrefix:@"/"]; - if (isAbsolutePath) { - rawPath = [rawPath substringFromIndex:1]; - } - NSMutableArray *components = [NSMutableArray arrayWithArray:[rawPath pathComponents]]; - for (int index = 0; index < [components count]; ++index) { - if ([[components objectAtIndex:index] isEqualToString:@".."]) { - [components removeObjectAtIndex:index]; - if (index > 0) { - [components removeObjectAtIndex:index-1]; - --index; - } - } - } - - if (isAbsolutePath) { - return [NSString stringWithFormat:@"/%@", [components componentsJoinedByString:@"/"]]; - } else { - return [components componentsJoinedByString:@"/"]; - } - - -} - -- (BOOL)valueForKeyIsNumber:(NSDictionary*)dict key:(NSString*)key -{ - BOOL bNumber = NO; - NSObject* value = dict[key]; - if (value) { - bNumber = [value isKindOfClass:[NSNumber class]]; - } - return bNumber; -} - -- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options -{ - CDVPluginResult* result = nil; - BOOL bDirRequest = NO; - BOOL create = NO; - BOOL exclusive = NO; - int errorCode = 0; // !!! risky - no error code currently defined for 0 - - if ([self valueForKeyIsNumber:options key:@"create"]) { - create = [(NSNumber*)[options valueForKey:@"create"] boolValue]; - } - if ([self valueForKeyIsNumber:options key:@"exclusive"]) { - exclusive = [(NSNumber*)[options valueForKey:@"exclusive"] boolValue]; - } - if ([self valueForKeyIsNumber:options key:@"getDir"]) { - // this will not exist for calls directly to getFile but will have been set by getDirectory before calling this method - bDirRequest = [(NSNumber*)[options valueForKey:@"getDir"] boolValue]; - } - // see if the requested path has invalid characters - should we be checking for more than just ":"? - if ([requestedPath rangeOfString:@":"].location != NSNotFound) { - errorCode = ENCODING_ERR; - } else { - // Build new fullPath for the requested resource. - // We concatenate the two paths together, and then scan the resulting string to remove - // parent ("..") references. Any parent references at the beginning of the string are - // silently removed. - NSString *combinedPath = [baseURI.fullPath stringByAppendingPathComponent:requestedPath]; - combinedPath = [self normalizePath:combinedPath]; - CDVFilesystemURL* requestedURL = [self URLforFullPath:combinedPath]; - - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir; - BOOL bExists = [fileMgr fileExistsAtPath:[self filesystemPathForURL:requestedURL] isDirectory:&bIsDir]; - if (bExists && (create == NO) && (bIsDir == !bDirRequest)) { - // path exists and is not of requested type - return TYPE_MISMATCH_ERR - errorCode = TYPE_MISMATCH_ERR; - } else if (!bExists && (create == NO)) { - // path does not exist and create is false - return NOT_FOUND_ERR - errorCode = NOT_FOUND_ERR; - } else if (bExists && (create == YES) && (exclusive == YES)) { - // file/dir already exists and exclusive and create are both true - return PATH_EXISTS_ERR - errorCode = PATH_EXISTS_ERR; - } else { - // if bExists and create == YES - just return data - // if bExists and create == NO - just return data - // if !bExists and create == YES - create and return data - BOOL bSuccess = YES; - NSError __autoreleasing* pError = nil; - if (!bExists && (create == YES)) { - if (bDirRequest) { - // create the dir - bSuccess = [fileMgr createDirectoryAtPath:[self filesystemPathForURL:requestedURL] withIntermediateDirectories:NO attributes:nil error:&pError]; - } else { - // create the empty file - bSuccess = [fileMgr createFileAtPath:[self filesystemPathForURL:requestedURL] contents:nil attributes:nil]; - } - } - if (!bSuccess) { - errorCode = ABORT_ERR; - if (pError) { - NSLog(@"error creating directory: %@", [pError localizedDescription]); - } - } else { - // NSLog(@"newly created file/dir (%@) exists: %d", reqFullPath, [fileMgr fileExistsAtPath:reqFullPath]); - // file existed or was created - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:requestedURL.fullPath isDirectory:bDirRequest]]; - } - } // are all possible conditions met? - } - - if (errorCode > 0) { - // create error callback - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - return result; - -} - -- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI -{ - CDVPluginResult* result = nil; - CDVFilesystemURL *newURI = nil; - if ([localURI.fullPath isEqualToString:@""]) { - // return self - newURI = localURI; - } else { - newURI = [CDVFilesystemURL fileSystemURLWithURL:[localURI.url URLByDeletingLastPathComponent]]; /* TODO: UGLY - FIX */ - } - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir; - BOOL bExists = [fileMgr fileExistsAtPath:[self filesystemPathForURL:newURI] isDirectory:&bIsDir]; - if (bExists) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:newURI.fullPath isDirectory:bIsDir]]; - } else { - // invalid path or file does not exist - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } - return result; -} - -- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options -{ - BOOL ok = NO; - - NSString* filePath = [self filesystemPathForURL:localURI]; - // we only care about this iCloud key for now. - // set to 1/true to skip backup, set to 0/false to back it up (effectively removing the attribute) - NSString* iCloudBackupExtendedAttributeKey = @"com.apple.MobileBackup"; - id iCloudBackupExtendedAttributeValue = [options objectForKey:iCloudBackupExtendedAttributeKey]; - - if ((iCloudBackupExtendedAttributeValue != nil) && [iCloudBackupExtendedAttributeValue isKindOfClass:[NSNumber class]]) { -// todo: fix me -// if (IsAtLeastiOSVersion(@"5.1")) { -// NSURL* url = [NSURL fileURLWithPath:filePath]; -// NSError* __autoreleasing error = nil; -// -// ok = [url setResourceValue:[NSNumber numberWithBool:[iCloudBackupExtendedAttributeValue boolValue]] forKey:NSURLIsExcludedFromBackupKey error:&error]; -// } else { // below 5.1 (deprecated - only really supported in 5.01) -// u_int8_t value = [iCloudBackupExtendedAttributeValue intValue]; -// if (value == 0) { // remove the attribute (allow backup, the default) -// ok = (removexattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], 0) == 0); -// } else { // set the attribute (skip backup) -// ok = (setxattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], &value, sizeof(value), 0, 0) == 0); -// } -// } - } - - if (ok) { - return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; - } -} - -/* remove the file or directory (recursively) - * IN: - * NSString* fullPath - the full path to the file or directory to be removed - * NSString* callbackId - * called from remove and removeRecursively - check all pubic api specific error conditions (dir not empty, etc) before calling - */ - -- (CDVPluginResult*)doRemove:(NSString*)fullPath -{ - CDVPluginResult* result = nil; - BOOL bSuccess = NO; - NSError* __autoreleasing pError = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - - @try { - bSuccess = [fileMgr removeItemAtPath:fullPath error:&pError]; - if (bSuccess) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - // see if we can give a useful error - CDVFileError errorCode = ABORT_ERR; - NSLog(@"error removing filesystem entry at %@: %@", fullPath, [pError localizedDescription]); - if ([pError code] == NSFileNoSuchFileError) { - errorCode = NOT_FOUND_ERR; - } else if ([pError code] == NSFileWriteNoPermissionError) { - errorCode = NO_MODIFICATION_ALLOWED_ERR; - } - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - } @catch(NSException* e) { // NSInvalidArgumentException if path is . or .. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:SYNTAX_ERR]; - } - - return result; -} - -- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI -{ - NSString *fileSystemPath = [self filesystemPathForURL:localURI]; - - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir = NO; - BOOL bExists = [fileMgr fileExistsAtPath:fileSystemPath isDirectory:&bIsDir]; - if (!bExists) { - return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } - if (bIsDir && ([[fileMgr contentsOfDirectoryAtPath:fileSystemPath error:nil] count] != 0)) { - // dir is not empty - return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR]; - } - return [self doRemove:fileSystemPath]; -} - -- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI -{ - NSString *fileSystemPath = [self filesystemPathForURL:localURI]; - return [self doRemove:fileSystemPath]; -} - -/* - * IN - * NSString localURI - * OUT - * NSString full local filesystem path for the represented file or directory, or nil if no such path is possible - * The file or directory does not necessarily have to exist. nil is returned if the filesystem type is not recognized, - * or if the URL is malformed. - * The incoming URI should be properly escaped (no raw spaces, etc. URI percent-encoding is expected). - */ -- (NSString *)fullPathForFileSystemPath:(NSString *)fsPath -{ - if ([fsPath hasPrefix:self.fsRoot]) { - return [fsPath substringFromIndex:[self.fsRoot length]]; - } - return nil; -} - - -- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI -{ - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSError* __autoreleasing error = nil; - NSString *fileSystemPath = [self filesystemPathForURL:localURI]; - - NSArray* contents = [fileMgr contentsOfDirectoryAtPath:fileSystemPath error:&error]; - - if (contents) { - NSMutableArray* entries = [NSMutableArray arrayWithCapacity:1]; - if ([contents count] > 0) { - // create an Entry (as JSON) for each file/dir - for (NSString* name in contents) { - // see if is dir or file - NSString* entryPath = [fileSystemPath stringByAppendingPathComponent:name]; - BOOL bIsDir = NO; - [fileMgr fileExistsAtPath:entryPath isDirectory:&bIsDir]; - NSDictionary* entryDict = [self makeEntryForPath:[self fullPathForFileSystemPath:entryPath] isDirectory:bIsDir]; - [entries addObject:entryDict]; - } - } - return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:entries]; - } else { - // assume not found but could check error for more specific error conditions - return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } -} - -- (unsigned long long)truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos -{ - unsigned long long newPos = 0UL; - - NSFileHandle* file = [NSFileHandle fileHandleForWritingAtPath:filePath]; - - if (file) { - [file truncateFileAtOffset:(unsigned long long)pos]; - newPos = [file offsetInFile]; - [file synchronizeFile]; - [file closeFile]; - } - return newPos; -} - -- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos -{ - unsigned long long newPos = [self truncateFile:[self filesystemPathForURL:localURI] atPosition:pos]; - return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(int)newPos]; -} - -- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend -{ - NSString *filePath = [self filesystemPathForURL:localURL]; - - CDVPluginResult* result = nil; - CDVFileError errCode = INVALID_MODIFICATION_ERR; - int bytesWritten = 0; - - if (filePath) { - NSOutputStream* fileStream = [NSOutputStream outputStreamToFileAtPath:filePath append:shouldAppend]; - if (fileStream) { - NSUInteger len = [encData length]; - if (len == 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:(double)len]; - } else { - [fileStream open]; - - bytesWritten = (int)[fileStream write:[encData bytes] maxLength:len]; - - [fileStream close]; - if (bytesWritten > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:bytesWritten]; - // } else { - // can probably get more detailed error info via [fileStream streamError] - // errCode already set to INVALID_MODIFICATION_ERR; - // bytesWritten = 0; // may be set to -1 on error - } - } - } // else fileStream not created return INVALID_MODIFICATION_ERR - } else { - // invalid filePath - errCode = NOT_FOUND_ERR; - } - if (!result) { - // was an error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode]; - } - return result; -} - -/** - * Helper function to check to see if the user attempted to copy an entry into its parent without changing its name, - * or attempted to copy a directory into a directory that it contains directly or indirectly. - * - * IN: - * NSString* srcDir - * NSString* destinationDir - * OUT: - * YES copy/ move is allows - * NO move is onto itself - */ -- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest -{ - // This weird test is to determine if we are copying or moving a directory into itself. - // Copy /Documents/myDir to /Documents/myDir-backup is okay but - // Copy /Documents/myDir to /Documents/myDir/backup not okay - BOOL copyOK = YES; - NSRange range = [dest rangeOfString:src]; - - if (range.location != NSNotFound) { - NSRange testRange = {range.length - 1, ([dest length] - range.length)}; - NSRange resultRange = [dest rangeOfString:@"/" options:0 range:testRange]; - if (resultRange.location != NSNotFound) { - copyOK = NO; - } - } - return copyOK; -} - -- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback -{ - NSFileManager *fileMgr = [[NSFileManager alloc] init]; - NSString *destRootPath = [self filesystemPathForURL:destURL]; - BOOL bDestIsDir = NO; - BOOL bDestExists = [fileMgr fileExistsAtPath:destRootPath isDirectory:&bDestIsDir]; - - NSString *newFileSystemPath = [destRootPath stringByAppendingPathComponent:newName]; - NSString *newFullPath = [self fullPathForFileSystemPath:newFileSystemPath]; - - BOOL bNewIsDir = NO; - BOOL bNewExists = [fileMgr fileExistsAtPath:newFileSystemPath isDirectory:&bNewIsDir]; - - CDVPluginResult *result = nil; - int errCode = 0; - - if (!bDestExists) { - // the destination root does not exist - errCode = NOT_FOUND_ERR; - } - - else if ([srcFs isKindOfClass:[CDVLocalFilesystem class]]) { - /* Same FS, we can shortcut with NSFileManager operations */ - NSString *srcFullPath = [srcFs filesystemPathForURL:srcURL]; - - BOOL bSrcIsDir = NO; - BOOL bSrcExists = [fileMgr fileExistsAtPath:srcFullPath isDirectory:&bSrcIsDir]; - - if (!bSrcExists) { - // the source does not exist - errCode = NOT_FOUND_ERR; - } else if ([newFileSystemPath isEqualToString:srcFullPath]) { - // source and destination can not be the same - errCode = INVALID_MODIFICATION_ERR; - } else if (bSrcIsDir && (bNewExists && !bNewIsDir)) { - // can't copy/move dir to file - errCode = INVALID_MODIFICATION_ERR; - } else { // no errors yet - NSError* __autoreleasing error = nil; - BOOL bSuccess = NO; - if (bCopy) { - if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFileSystemPath]) { - // can't copy dir into self - errCode = INVALID_MODIFICATION_ERR; - } else if (bNewExists) { - // the full destination should NOT already exist if a copy - errCode = PATH_EXISTS_ERR; - } else { - bSuccess = [fileMgr copyItemAtPath:srcFullPath toPath:newFileSystemPath error:&error]; - } - } else { // move - // iOS requires that destination must not exist before calling moveTo - // is W3C INVALID_MODIFICATION_ERR error if destination dir exists and has contents - // - if (!bSrcIsDir && (bNewExists && bNewIsDir)) { - // can't move a file to directory - errCode = INVALID_MODIFICATION_ERR; - } else if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFileSystemPath]) { - // can't move a dir into itself - errCode = INVALID_MODIFICATION_ERR; - } else if (bNewExists) { - if (bNewIsDir && ([[fileMgr contentsOfDirectoryAtPath:newFileSystemPath error:NULL] count] != 0)) { - // can't move dir to a dir that is not empty - errCode = INVALID_MODIFICATION_ERR; - newFileSystemPath = nil; // so we won't try to move - } else { - // remove destination so can perform the moveItemAtPath - bSuccess = [fileMgr removeItemAtPath:newFileSystemPath error:NULL]; - if (!bSuccess) { - errCode = INVALID_MODIFICATION_ERR; // is this the correct error? - newFileSystemPath = nil; - } - } - } else if (bNewIsDir && [newFileSystemPath hasPrefix:srcFullPath]) { - // can't move a directory inside itself or to any child at any depth; - errCode = INVALID_MODIFICATION_ERR; - newFileSystemPath = nil; - } - - if (newFileSystemPath != nil) { - bSuccess = [fileMgr moveItemAtPath:srcFullPath toPath:newFileSystemPath error:&error]; - } - } - if (bSuccess) { - // should verify it is there and of the correct type??? - NSDictionary* newEntry = [self makeEntryForPath:newFullPath isDirectory:bSrcIsDir]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry]; - } else { - if (error) { - if (([error code] == NSFileReadUnknownError) || ([error code] == NSFileReadTooLargeError)) { - errCode = NOT_READABLE_ERR; - } else if ([error code] == NSFileWriteOutOfSpaceError) { - errCode = QUOTA_EXCEEDED_ERR; - } else if ([error code] == NSFileWriteNoPermissionError) { - errCode = NO_MODIFICATION_ALLOWED_ERR; - } - } - } - } - } else { - // Need to copy the hard way - [srcFs readFileAtURL:srcURL start:0 end:-1 callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - BOOL bSuccess = [data writeToFile:newFileSystemPath atomically:YES]; - if (bSuccess) { - // should verify it is there and of the correct type??? - NSDictionary* newEntry = [self makeEntryForPath:newFullPath isDirectory:NO]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ABORT_ERR]; - } - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - callback(result); - }]; - return; // Async IO; return without callback. - } - if (result == nil) { - if (!errCode) { - errCode = INVALID_MODIFICATION_ERR; // Catch-all default - } - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errCode]; - } - callback(result); -} - -/* helper function to get the mimeType from the file extension - * IN: - * NSString* fullPath - filename (may include path) - * OUT: - * NSString* the mime type as type/subtype. nil if not able to determine - */ -+ (NSString*)getMimeTypeFromPath:(NSString*)fullPath -{ - NSString* mimeType = nil; - - if (fullPath) { - CFStringRef typeId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[fullPath pathExtension], NULL); - if (typeId) { - mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType); - if (!mimeType) { - // special case for m4a - if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) { - mimeType = @"audio/mp4"; - } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) { - mimeType = @"audio/wav"; - } else if ([[fullPath pathExtension] rangeOfString:@"css"].location != NSNotFound) { - mimeType = @"text/css"; - } - } - CFRelease(typeId); - } - } - return mimeType; -} - -- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback -{ - NSString *path = [self filesystemPathForURL:localURL]; - - NSString* mimeType = [CDVLocalFilesystem getMimeTypeFromPath:path]; - if (mimeType == nil) { - mimeType = @"*/*"; - } - NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:path]; - if (start > 0) { - [file seekToFileOffset:start]; - } - - NSData* readData; - if (end < 0) { - readData = [file readDataToEndOfFile]; - } else { - readData = [file readDataOfLength:(end - start)]; - } - [file closeFile]; - - callback(readData, mimeType, readData != nil ? NO_ERROR : NOT_FOUND_ERR); -} - -- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback -{ - NSString *path = [self filesystemPathForURL:localURL]; - CDVPluginResult *result; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - - NSError* __autoreleasing error = nil; - NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:path error:&error]; - - if (fileAttrs) { - - // create dictionary of file info - NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5]; - - [fileInfo setObject:localURL.fullPath forKey:@"fullPath"]; - [fileInfo setObject:@"" forKey:@"type"]; // can't easily get the mimetype unless create URL, send request and read response so skipping - [fileInfo setObject:[path lastPathComponent] forKey:@"name"]; - - // Ensure that directories (and other non-regular files) report size of 0 - unsigned long long size = ([fileAttrs fileType] == NSFileTypeRegular ? [fileAttrs fileSize] : 0); - [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:size] forKey:@"size"]; - - NSDate* modDate = [fileAttrs fileModificationDate]; - if (modDate) { - [fileInfo setObject:[NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000] forKey:@"lastModifiedDate"]; - } - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]; - - } else { - // didn't get fileAttribs - CDVFileError errorCode = ABORT_ERR; - NSLog(@"error getting metadata: %@", [error localizedDescription]); - if ([error code] == NSFileNoSuchFileError || [error code] == NSFileReadNoSuchFileError) { - errorCode = NOT_FOUND_ERR; - } - // log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode]; - } - - callback(result); -} - -@end diff --git a/src/windows/FileProxy.js b/src/windows/FileProxy.js deleted file mode 100644 index eb4a7ee88..000000000 --- a/src/windows/FileProxy.js +++ /dev/null @@ -1,1175 +0,0 @@ -/* - * - * 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 */ -/* eslint prefer-regex-literals: 0 */ - -const File = require('./File'); -const FileError = require('./FileError'); -const Flags = require('./Flags'); -const FileSystem = require('./FileSystem'); -const LocalFileSystem = require('./LocalFileSystem'); -const 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; -} - -const FileEntry = function (name, fullPath, filesystemName, nativeURL) { - FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath, filesystemName, nativeURL]); -}; - -utils.extend(FileEntry, Entry); - -const DirectoryEntry = function (name, fullPath, filesystemName, nativeURL) { - DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath, filesystemName, nativeURL); -}; - -utils.extend(DirectoryEntry, Entry); - -const getFolderFromPathAsync = Windows.Storage.StorageFolder.getFolderFromPathAsync; -const getFileFromPathAsync = Windows.Storage.StorageFile.getFileFromPathAsync; - -function writeBytesAsync (storageFile, data, position) { - return storageFile.openAsync(Windows.Storage.FileAccessMode.readWrite) - .then(function (output) { - output.seek(position); - const 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); - const 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); - const dataSize = data.size; - const 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 \\ - let cleanPath = path.replace(/\//g, '\\'); - // turn \\ into \ - cleanPath = cleanPath.replace(/\\+/g, '\\'); - return cleanPath; -} - -function nativePathToCordova (path) { - const cleanPath = path.replace(/\\/g, '/'); - return cleanPath; -} - -const driveRE = new RegExp('^[/]*([A-Z]:)'); -const invalidNameRE = /[\\?*|"<>:]/; -function validName (name) { - return !invalidNameRE.test(name.replace(driveRE, '')); -} - -function sanitize (path) { - const slashesRE = new RegExp('/{2,}', 'g'); - const components = path.replace(slashesRE, '/').split(/\/+/); - // Remove double dots, use old school array iteration instead of RegExp - // since it is impossible to debug them - for (let 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('/'); -} - -const 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 - const regLeadingSlashes = /^\/*/; - const 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) { - const path = sanitize('/' + this.name + (fullPath[0] === '/' ? '' : '/') + FileSystem.encodeURIPath(fullPath)); - return 'cdvfile://localhost' + path; -}; - -const windowsPaths = { - dataDirectory: 'ms-appdata:///local/', - cacheDirectory: 'ms-appdata:///temp/', - tempDirectory: 'ms-appdata:///temp/', - syncedDataDirectory: 'ms-appdata:///roaming/', - applicationDirectory: 'ms-appx:///', - applicationStorageDirectory: 'ms-appx:///' -}; - -let 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) { - let res; - const allfs = getAllFS(); - Object.keys(allfs).some(function (fsn) { - const fs = allfs[fsn]; - if (path.indexOf(fs.winpath) === 0) { res = fs; } - return res; - }); - return res; -} - -const msapplhRE = new RegExp('^ms-appdata://localhost/'); -function pathFromURL (url) { - url = url.replace(msapplhRE, 'ms-appdata:///'); - let 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); - } - } - - // eslint-disable-next-line - ['file://', 'ms-appdata:///', 'ms-appx://', 'cdvfile://localhost/'].every(function (p) { - if (path.indexOf(p) !== 0) { return true; } - const 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:///'); - let res; - if (url.indexOf('file:/') === 0) { res = getFilesystemFromPath(pathFromURL(url)); } else { - const allfs = getAllFS(); - Object.keys(allfs).every(function (fsn) { - const 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) { - const path = nativePathToCordova(wpath); - if (path.indexOf(fs.winpath) !== 0) { return null; } - return path.replace(fs.winpath, '/'); -} - -const 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 }); - }, - 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; - } - let todo = the.files.length; - const copyfolders = function () { - if (!(todo--)) { - complete(); - return; - } - copyFolder(the.folders[todo], dst).done(function () { copyfolders(); }, failed); - }; - const 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; - } - let todo = the.files.length; - const movefolders = function () { - if (!(todo--)) { - src.deleteAsync().done(complete, failed); - return; - } - moveFolder(the.folders[todo], the.fld).done(movefolders, failed); - }; - const 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"] - const src = args[0]; - const parent = args[1]; - const name = args[2]; - - const srcFS = getFilesystemFromURL(src); - const dstFS = getFilesystemFromURL(parent); - const srcPath = pathFromURL(src); - const dstPath = pathFromURL(parent); - if (!(srcFS && dstFS && validName(name))) { - fail(FileError.ENCODING_ERR); - return; - } - - const srcWinPath = cordovaPathToNative(sanitize(srcFS.winpath + srcPath)); - const dstWinPath = cordovaPathToNative(sanitize(dstFS.winpath + dstPath)); - const tgtFsPath = sanitize(dstPath + '/' + name); - const 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) { - const fs = getFilesystemFromURL(args[0]); - const path = pathFromURL(args[0]); - if (!fs || !validName(path)) { - fail(FileError.ENCODING_ERR); - return; - } - const fullPath = cordovaPathToNative(fs.winpath + path); - - const 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); - } - ); - }; - - const getMetadataForFolder = function (storageFolder) { - storageFolder.getBasicPropertiesAsync().then( - function (basicProperties) { - const 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"] - const fs = getFilesystemFromURL(args[0]); - const 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; - } - - const parpath = path.replace(new RegExp('/[^/]+/?$', 'g'), ''); - const parname = path.substr(parpath.length); - const fullPath = cordovaPathToNative(fs.winpath + parpath); - - const 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) { - const url = args[0]; - const enc = args[1]; - let startPos = args[2]; - let endPos = args[3]; - - const fs = getFilesystemFromURL(url); - const path = pathFromURL(url); - if (!fs) { - fail(FileError.ENCODING_ERR); - return; - } - const wpath = cordovaPathToNative(sanitize(fs.winpath + path)); - - let 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); - - const readSize = endPos - startPos; - const 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) { - const url = args[0]; - const startPos = args[1]; - const endPos = args[2]; - - const fs = getFilesystemFromURL(url); - const path = pathFromURL(url); - if (!fs) { - fail(FileError.ENCODING_ERR); - return; - } - const wpath = cordovaPathToNative(sanitize(fs.winpath + path)); - - getFileFromPathAsync(wpath).then( - function (storageFile) { - Windows.Storage.FileIO.readBufferAsync(storageFile).done( - function (buffer) { - const dataReader = Windows.Storage.Streams.DataReader.fromBuffer(buffer); - // var fileContent = dataReader.readString(buffer.length); - const byteArray = new Uint8Array(buffer.length); - let byteString = ''; - dataReader.readBytes(byteArray); - dataReader.close(); - for (let i = 0; i < byteArray.length; i++) { - const charByte = byteArray[i]; - // var charRepresentation = charByte <= 127 ? String.fromCharCode(charByte) : charByte.toString(16); - const charRepresentation = String.fromCharCode(charByte); - byteString += charRepresentation; - } - win(byteString.slice(startPos, endPos)); - } - ); - }, function () { - fail(FileError.NOT_FOUND_ERR); - } - ); - }, - - readAsArrayBuffer: function (win, fail, args) { - const url = args[0]; - const fs = getFilesystemFromURL(url); - const path = pathFromURL(url); - if (!fs) { - fail(FileError.ENCODING_ERR); - return; - } - const wpath = cordovaPathToNative(sanitize(fs.winpath + path)); - - getFileFromPathAsync(wpath).then( - function (storageFile) { - const blob = MSApp.createFileFromStorageFile(storageFile); - const url = URL.createObjectURL(blob, { oneTimeOnly: true }); // eslint-disable-line no-undef - const xhr = new XMLHttpRequest(); // eslint-disable-line no-undef - xhr.open('GET', url, true); - xhr.responseType = 'arraybuffer'; - xhr.onload = function () { - let resultArrayBuffer = xhr.response; - // get start and end position of bytes in buffer to be returned - const startPos = args[1] || 0; - const 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 - const tempArray = new Uint8Array(resultArrayBuffer); - const resBuffer = new ArrayBuffer(endPos - startPos); - const resArray = new Uint8Array(resBuffer); - - for (let 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) { - const url = args[0]; - const fs = getFilesystemFromURL(url); - const path = pathFromURL(url); - if (!fs) { - fail(FileError.ENCODING_ERR); - return; - } - const wpath = cordovaPathToNative(sanitize(fs.winpath + path)); - - getFileFromPathAsync(wpath).then( - function (storageFile) { - Windows.Storage.FileIO.readBufferAsync(storageFile).done( - function (buffer) { - let 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); - } - const mediaType = storageFile.contentType; - const result = 'data:' + mediaType + ';base64,' + strBase64; - win(result); - } - ); - }, function () { - fail(FileError.NOT_FOUND_ERR); - } - ); - }, - - getDirectory: function (win, fail, args) { - const dirurl = args[0]; - const path = args[1]; - const options = args[2]; - - const fs = getFilesystemFromURL(dirurl); - const dirpath = pathFromURL(dirurl); - if (!fs || !validName(path)) { - fail(FileError.ENCODING_ERR); - return; - } - const fspath = sanitize(dirpath + '/' + path); - const completePath = sanitize(fs.winpath + fspath); - - const name = completePath.substring(completePath.lastIndexOf('/') + 1); - - const wpath = cordovaPathToNative(completePath.substring(0, completePath.lastIndexOf('/'))); - - let 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 n/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) { - const fs = getFilesystemFromURL(args[0]); - const 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; - } - const 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) { - const fs = getFilesystemFromURL(args[0]); - const 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; - } - const 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) { - const dirurl = args[0]; - const path = args[1]; - const options = args[2]; - - const fs = getFilesystemFromURL(dirurl); - const dirpath = pathFromURL(dirurl); - if (!fs || !validName(path)) { - fail(FileError.ENCODING_ERR); - return; - } - const fspath = sanitize(dirpath + '/' + path); - const completePath = sanitize(fs.winpath + fspath); - - const fileName = completePath.substring(completePath.lastIndexOf('/') + 1); - - const wpath = cordovaPathToNative(completePath.substring(0, completePath.lastIndexOf('/'))); - - let 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"] - const fs = getFilesystemFromURL(args[0]); - const path = pathFromURL(args[0]); - if (!fs || !validName(path)) { - fail(FileError.ENCODING_ERR); - return; - } - const fullPath = cordovaPathToNative(fs.winpath + path); - - const result = []; - - getFolderFromPathAsync(fullPath).done(function (storageFolder) { - const promiseArr = []; - let index = 0; - promiseArr[index++] = storageFolder.getFilesAsync().then(function (fileList) { - if (fileList !== null) { - for (let i = 0; i < fileList.length; i++) { - const 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 (let j = 0; j < folderList.length; j++) { - const 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) { - const url = args[0]; - const data = args[1]; - const position = args[2]; - const isBinary = args[3]; - - const fs = getFilesystemFromURL(url); - const path = pathFromURL(url); - if (!fs) { - fail(FileError.ENCODING_ERR); - return; - } - const completePath = sanitize(fs.winpath + path); - const fileName = completePath.substring(completePath.lastIndexOf('/') + 1); - const dirpath = completePath.substring(0, completePath.lastIndexOf('/')); - const 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'); - } - - const 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) { - const 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"] - const url = args[0]; - const size = args[1]; - - const fs = getFilesystemFromURL(url); - const path = pathFromURL(url); - if (!fs) { - fail(FileError.ENCODING_ERR); - return; - } - const completePath = sanitize(fs.winpath + path); - const wpath = cordovaPathToNative(completePath); - const dirwpath = cordovaPathToNative(completePath.substring(0, completePath.lastIndexOf('/'))); - - getFileFromPathAsync(wpath).done(function (storageFile) { - // the current length of the file. - let 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); - const 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) { - const type = args[0]; - const size = args[1]; - const MAX_SIZE = 10000000000; - if (size > MAX_SIZE) { - fail(FileError.QUOTA_EXCEEDED_ERR); - return; - } - - let 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) { - const uri = args[0]; - - let path = pathFromURL(uri); - const fs = getFilesystemFromURL(uri); - if (!fs || !validName(path)) { - fail(FileError.ENCODING_ERR); - return; - } - if (path.indexOf(fs.winpath) === 0) { path = path.substr(fs.winpath.length); } - const 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); diff --git a/tests/tests.js b/tests/tests.js index 84da3626e..5656fab0c 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -29,7 +29,6 @@ exports.defineAutoTests = function () { const isIE = isBrowser && (window.msIndexedDB); const isIndexedDBShim = isBrowser && !isChrome; // Firefox and IE for example - const isWindows = cordova.platformId === 'windows'; /* eslint-enable no-undef */ const MEDIUM_TIMEOUT = 15000; @@ -3448,10 +3447,6 @@ exports.defineAutoTests = function () { it('file.spec.114 fileEntry should have a toNativeURL method', function (done) { const fileName = 'native.file.uri'; - if (isWindows) { - const rootPath = root.fullPath; - pathExpect = rootPath.substr(0, rootPath.indexOf(':')); - } // create a new file entry createFile(fileName, function (entry) { expect(entry.toNativeURL).toBeDefined(); @@ -3796,8 +3791,6 @@ exports.defineAutoTests = function () { } } else if (cordova.platformId === 'ios') { expectedPaths.push('syncedDataDirectory', 'documentsDirectory', 'tempDirectory'); - } else if (cordova.platformId === 'osx') { - expectedPaths.push('documentsDirectory', 'tempDirectory', 'rootDirectory'); } else { console.log('Skipping test due on unsupported platform.'); return; @@ -4207,9 +4200,7 @@ exports.defineManualTests = function (contentEl, createActionButton) { const fsRoots = { ios: 'library,library-nosync,documents,documents-nosync,cache,bundle,root,private', - osx: 'library,library-nosync,documents,documents-nosync,cache,bundle,root,private', - android: 'files,files-external,documents,sdcard,cache,cache-external,assets,root', - windows: 'temporary,persistent' + android: 'files,files-external,documents,sdcard,cache,cache-external,assets,root' }; // Add title and align to content diff --git a/types/index.d.ts b/types/index.d.ts index aeb3e30c5..a59024dbb 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -366,8 +366,6 @@ interface Cordova { syncedDataDirectory: string; /* iOS: Files private to the app, but that are meaningful to other applciations (e.g. Office files) */ documentsDirectory: string; - /* BlackBerry10: Files globally available to all apps */ - sharedDirectory: string } } diff --git a/www/FileReader.js b/www/FileReader.js index a8af9239b..466e0ce07 100644 --- a/www/FileReader.js +++ b/www/FileReader.js @@ -135,11 +135,7 @@ function readSuccessCallback (readType, encoding, offset, totalSize, accumulate, let CHUNK_SIZE = FileReader.READ_CHUNK_SIZE; if (readType === 'readAsDataURL') { - // Windows proxy does not support reading file slices as Data URLs - // so read the whole file at once. - CHUNK_SIZE = cordova.platformId === 'windows' - ? totalSize - : ( + CHUNK_SIZE = ( // Calculate new chunk size for data URLs to be multiply of 3 // Otherwise concatenated base64 chunks won't be valid base64 data FileReader.READ_CHUNK_SIZE - (FileReader.READ_CHUNK_SIZE % 3) + 3 diff --git a/www/FileWriter.js b/www/FileWriter.js index 8144fa0d5..b8ba6b2f6 100644 --- a/www/FileWriter.js +++ b/www/FileWriter.js @@ -111,11 +111,9 @@ FileWriter.prototype.abort = function () { FileWriter.prototype.write = function (data, isPendingBlobReadResult) { const that = this; const supportsBinary = (typeof window.Blob !== 'undefined' && typeof window.ArrayBuffer !== 'undefined'); - /* eslint-disable no-undef */ - const isProxySupportBlobNatively = cordova.platformId === 'windows'; // Check to see if the incoming data is a blob - if (data instanceof File || (!isProxySupportBlobNatively && supportsBinary && data instanceof Blob)) { + if (data instanceof File || (supportsBinary && data instanceof Blob)) { const fileReader = new FileReader(); /* eslint-enable no-undef */ fileReader.onload = function () { diff --git a/www/fileSystemPaths.js b/www/fileSystemPaths.js index 494188981..bfa491238 100644 --- a/www/fileSystemPaths.js +++ b/www/fileSystemPaths.js @@ -46,8 +46,6 @@ exports.file = { syncedDataDirectory: null, // iOS: Files private to the app, but that are meaningful to other applications (e.g. Office files) documentsDirectory: null, - // BlackBerry10: Files globally available to all apps - sharedDirectory: null }; channel.waitForInitialization('onFileSystemPathsReady'); diff --git a/www/fileSystems-roots.js b/www/fileSystems-roots.js index 12b6b4be4..76eed4a8b 100644 --- a/www/fileSystems-roots.js +++ b/www/fileSystems-roots.js @@ -24,7 +24,7 @@ let fsMap = null; const FileSystem = require('./FileSystem'); const exec = require('cordova/exec'); -// Overridden by Android, BlackBerry 10 and iOS to populate fsMap. +// Overridden by Android and iOS to populate fsMap. require('./fileSystems').getFs = function (name, callback) { function success (response) { fsMap = {}; diff --git a/www/fileSystems.js b/www/fileSystems.js index 40e557481..93d022dca 100644 --- a/www/fileSystems.js +++ b/www/fileSystems.js @@ -19,7 +19,7 @@ * */ -// Overridden by Android, BlackBerry 10 and iOS to populate fsMap. +// Overridden by Android and iOS to populate fsMap. module.exports.getFs = function (name, callback) { callback(null); }; diff --git a/www/requestFileSystem.js b/www/requestFileSystem.js index f7c17223e..0e674106c 100644 --- a/www/requestFileSystem.js +++ b/www/requestFileSystem.js @@ -61,10 +61,6 @@ if (file_system) { if (successCallback) { fileSystems.getFs(file_system.name, function (fs) { - // This should happen only on platforms that haven't implemented requestAllFileSystems (windows) - if (!fs) { - fs = new FileSystem(file_system.name, file_system.root); - } successCallback(fs); }); } diff --git a/www/resolveLocalFileSystemURI.js b/www/resolveLocalFileSystemURI.js index ca8d67d97..ef3788b6d 100644 --- a/www/resolveLocalFileSystemURI.js +++ b/www/resolveLocalFileSystemURI.js @@ -67,10 +67,6 @@ // create appropriate Entry object const fsName = entry.filesystemName || (entry.filesystem && entry.filesystem.name) || (entry.filesystem === window.PERSISTENT ? 'persistent' : 'temporary'); fileSystems.getFs(fsName, function (fs) { - // This should happen only on platforms that haven't implemented requestAllFileSystems (windows) - if (!fs) { - fs = new FileSystem(fsName, { name: '', fullPath: '/' }); - } const result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath, fs, entry.nativeURL) : new FileEntry(entry.name, entry.fullPath, fs, entry.nativeURL); successCallback(result); });