You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ia...@apache.org on 2013/11/18 20:55:33 UTC
[1/6] git commit: CB-5408: Add handler for filesystem:// urls
Updated Branches:
refs/heads/dev 1dfdf0f81 -> 7bb397771
CB-5408: Add handler for filesystem:// urls
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/b8c4f85e
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/b8c4f85e
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/b8c4f85e
Branch: refs/heads/dev
Commit: b8c4f85eb56ca51fec08cf8a1fbc926f56ac4e7e
Parents: b3b6a83
Author: Ian Clelland <ic...@chromium.org>
Authored: Fri Nov 8 15:11:13 2013 -0500
Committer: Ian Clelland <ic...@chromium.org>
Committed: Mon Nov 18 14:53:40 2013 -0500
----------------------------------------------------------------------
src/ios/CDVFile.m | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/b8c4f85e/src/ios/CDVFile.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVFile.m b/src/ios/CDVFile.m
index 2f41046..29a3241 100644
--- a/src/ios/CDVFile.m
+++ b/src/ios/CDVFile.m
@@ -25,6 +25,8 @@
#import <MobileCoreServices/MobileCoreServices.h>
#import <sys/xattr.h>
+static CDVFile *filePlugin = nil;
+
@interface CDVFilesystemURL : NSObject {
NSURL *url_;
CDVFileSystemType fileSystemType_;
@@ -71,6 +73,56 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import)
NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
NSString* const kCDVAssetsLibraryScheme = @"assets-library";
+@interface CDVFilesystemURLProtocol : NSURLProtocol
+@end
+
+@implementation CDVFilesystemURLProtocol
+
+NSString* const kCDVFilesystemURLPrefix = @"filesystem";
+
++ (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
+{
+ NSURL *url = [[self request] URL];
+ NSString *pathString = [url relativePath];
+ pathString = [filePlugin fileSystemPathForLocalURI:url];
+ [CDVFile readFileWithPath:pathString start:0 end:-1 callback:^void(NSData *data, NSString *mimetype, CDVFileError error) {
+ if (!error) {
+ NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url statusCode:200 HTTPVersion:@"HTTP/1.1"headerFields:@{@"Content-Type": mimetype}];
+ [[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 statusCode:404 HTTPVersion:@"HTTP/1.1"headerFields:@{}];
+ [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+ [[self client] URLProtocolDidFinishLoading:self];
+ }
+ }];
+}
+
+- (void)stopLoading
+{
+ // do any cleanup here
+}
+
+@end
+
+
@implementation CDVFile
@synthesize appDocsPath, appLibraryPath, appTempPath, persistentPath, temporaryPath, userHasAllowed;
@@ -79,6 +131,9 @@ NSString* const kCDVAssetsLibraryScheme = @"assets-library";
{
self = (CDVFile*)[super initWithWebView:theWebView];
if (self) {
+ filePlugin = self;
+ [NSURLProtocol registerClass:[CDVFilesystemURLProtocol class]];
+
// get the documents directory path
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
self.appDocsPath = [paths objectAtIndex:0];
[6/6] git commit: CB-5406: Split iOS file plugin into modules
Posted by ia...@apache.org.
CB-5406: Split iOS file plugin into modules
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/7bb39777
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/7bb39777
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/7bb39777
Branch: refs/heads/dev
Commit: 7bb397771431c24ae4fdbe4c5d5f745479689904
Parents: 64187ca
Author: Ian Clelland <ic...@chromium.org>
Authored: Mon Nov 18 14:52:14 2013 -0500
Committer: Ian Clelland <ic...@chromium.org>
Committed: Mon Nov 18 14:54:01 2013 -0500
----------------------------------------------------------------------
plugin.xml | 4 +
src/ios/CDVAssetLibraryFilesystem.h | 28 +
src/ios/CDVAssetLibraryFilesystem.m | 247 +++++++++
src/ios/CDVFile.h | 37 +-
src/ios/CDVFile.m | 878 +------------------------------
src/ios/CDVLocalFilesystem.h | 30 ++
src/ios/CDVLocalFilesystem.m | 655 +++++++++++++++++++++++
7 files changed, 1003 insertions(+), 876 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7bb39777/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index d4091f8..6743c1b 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -113,6 +113,10 @@ xmlns:android="http://schemas.android.com/apk/res/android"
</config-file>
<header-file src="src/ios/CDVFile.h" />
<source-file src="src/ios/CDVFile.m" />
+ <header-file src="src/ios/CDVLocalFilesystem.h" />
+ <source-file src="src/ios/CDVLocalFilesystem.m" />
+ <header-file src="src/ios/CDVAssetLibraryFilesystem.h" />
+ <source-file src="src/ios/CDVAssetLibraryFilesystem.m" />
<!-- ios specific file apis -->
<js-module src="www/ios/Entry.js" name="iosEntry">
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7bb39777/src/ios/CDVAssetLibraryFilesystem.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVAssetLibraryFilesystem.h b/src/ios/CDVAssetLibraryFilesystem.h
new file mode 100644
index 0000000..295a3d8
--- /dev/null
+++ b/src/ios/CDVAssetLibraryFilesystem.h
@@ -0,0 +1,28 @@
+/*
+ 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"
+
+extern NSString* const kCDVAssetsLibraryPrefix;
+extern NSString* const kCDVAssetsLibraryScheme;
+
+@interface CDVAssetLibraryFilesystem : NSObject<CDVFileSystem> {
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7bb39777/src/ios/CDVAssetLibraryFilesystem.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVAssetLibraryFilesystem.m b/src/ios/CDVAssetLibraryFilesystem.m
new file mode 100644
index 0000000..a266786
--- /dev/null
+++ b/src/ios/CDVAssetLibraryFilesystem.m
@@ -0,0 +1,247 @@
+/*
+ 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 "CDVAssetLibraryFilesystem.h"
+#import <Cordova/CDV.h>
+#import <AssetsLibrary/ALAsset.h>
+#import <AssetsLibrary/ALAssetRepresentation.h>
+#import <AssetsLibrary/ALAssetsLibrary.h>
+#import <MobileCoreServices/MobileCoreServices.h>
+
+NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
+NSString* const kCDVAssetsLibraryScheme = @"assets-library";
+
+@implementation CDVAssetLibraryFilesystem
+- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url
+{
+ NSDictionary* fileSystem = [self makeEntryForPath:[url.url absoluteString] fileSystem:ASSETS_LIBRARY isDirectory:NO];
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
+}
+
+- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystem:(int)fsType isDirectory:(BOOL)isDir
+{
+ NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5];
+ NSString* lastPart = [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: [NSNumber numberWithInt:fsType] forKey: @"filesystem"];
+
+ return dirEntry;
+}
+
+/* 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";
+ }
+ }
+ CFRelease(typeId);
+ }
+ }
+ return mimeType;
+}
+
+- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options
+{
+ // return unsupported result for assets-library URLs
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFile not supported for assets-library URLs."];
+}
+
+- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI
+{
+ // we don't (yet?) support getting the parent of an asset
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
+}
+
+- (void)getMetadataForURL:(CDVFilesystemURL *)url callback:(void (^)(CDVPluginResult *))callback
+{
+ __block CDVPluginResult* result = nil;
+
+ // In this case, we need to use an asynchronous method to retrieve the file.
+ // Because of this, we can't just assign to `result` and send it at the end of the method.
+ // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
+ ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
+ if (asset) {
+ // We have the asset! Retrieve the metadata and send it off.
+ NSDate* date = [asset valueForProperty:ALAssetPropertyDate];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[date timeIntervalSince1970] * 1000];
+ callback(result);
+ } else {
+ // We couldn't find the asset. Send the appropriate error.
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+ callback(result);
+ }
+ };
+ // TODO(maxw): Consider making this a class variable since it's the same every time.
+ ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
+ // Retrieving the asset failed for some reason. Send the appropriate error.
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
+ callback(result);
+ };
+
+ ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+ [assetsLibrary assetForURL:url.url resultBlock:resultBlock failureBlock:failureBlock];
+ return;
+}
+
+- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options
+{
+ // setMetadata doesn't make sense for asset library files
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
+}
+
+- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI
+{
+ // return error for assets-library URLs
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
+}
+
+- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI
+{
+ // return error for assets-library URLs
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"removeRecursively not supported for assets-library URLs."];
+}
+
+- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI
+{
+ // return unsupported result for assets-library URLs
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readEntries not supported for assets-library URLs."];
+}
+
+- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos
+{
+ // assets-library files can't be truncated
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
+}
+
+- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend
+{
+ // text can't be written into assets-library files
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
+}
+
+- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject<CDVFileSystem> *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback
+{
+ // Copying to an assets library file is not doable, since we can't write it.
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
+ callback(result);
+}
+
+- (NSString *)fileSystemPathForURL:(CDVFilesystemURL *)url
+{
+ NSString *path = nil;
+ if ([[url.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
+ path = [url.url path];
+ } else {
+ path = url.fullPath;
+ }
+ if ([path hasSuffix:@"/"]) {
+ path = [path substringToIndex:([path length]-1)];
+ }
+ return path;
+}
+
+- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback
+{
+ NSString *path = [self fileSystemPathForURL:localURL];
+
+ ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
+ if (asset) {
+ // We have the asset! Get the data and send it off.
+ ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
+ Byte* buffer = (Byte*)malloc([assetRepresentation size]);
+ NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
+ NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
+ NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType);
+
+ callback(data, MIMEType, NO_ERROR);
+ } else {
+ callback(nil, nil, NOT_FOUND_ERR);
+ }
+ };
+
+ ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
+ // Retrieving the asset failed for some reason. Send the appropriate error.
+ NSLog(@"Error: %@", error);
+ callback(nil, nil, SECURITY_ERR);
+ };
+
+ ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+ [assetsLibrary assetForURL:[NSURL URLWithString:path] resultBlock:resultBlock failureBlock:failureBlock];
+}
+
+- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback
+{
+ NSString *path = [self fileSystemPathForURL:localURL];
+
+ // In this case, we need to use an asynchronous method to retrieve the file.
+ // Because of this, we can't just assign to `result` and send it at the end of the method.
+ // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
+ ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
+ if (asset) {
+ // We have the asset! Populate the dictionary and send it off.
+ NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
+ ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
+ [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"];
+ [fileInfo setObject:localURL.fullPath forKey:@"fullPath"];
+ NSString* filename = [assetRepresentation filename];
+ [fileInfo setObject:filename forKey:@"name"];
+ [fileInfo setObject:[CDVAssetLibraryFilesystem getMimeTypeFromPath:filename] forKey:@"type"];
+ NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate];
+ NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000];
+ [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
+
+ callback([CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]);
+ } else {
+ // We couldn't find the asset. Send the appropriate error.
+ callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]);
+ }
+ };
+ ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
+ // Retrieving the asset failed for some reason. Send the appropriate error.
+ callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]);
+ };
+
+ ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+ [assetsLibrary assetForURL:[NSURL URLWithString:path] resultBlock:resultBlock failureBlock:failureBlock];
+ return;
+}
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7bb39777/src/ios/CDVFile.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVFile.h b/src/ios/CDVFile.h
index ef17a62..0f6d618 100644
--- a/src/ios/CDVFile.h
+++ b/src/ios/CDVFile.h
@@ -44,7 +44,42 @@ enum CDVFileSystemType {
};
typedef int CDVFileSystemType;
-extern NSString* const kCDVAssetsLibraryPrefix;
+@interface CDVFilesystemURL : NSObject {
+ NSURL *_url;
+ CDVFileSystemType _fileSystemType;
+ NSString *_fullPath;
+}
+
+- (id) initWithString:(NSString*)strURL;
+- (id) initWithURL:(NSURL*)URL;
++ (CDVFilesystemURL *)fileSystemURLWithString:(NSString *)strURL;
++ (CDVFilesystemURL *)fileSystemURLWithURL:(NSURL *)URL;
+
+
+@property (atomic) NSURL *url;
+@property (atomic) CDVFileSystemType fileSystemType;
+@property (atomic) NSString *fullPath;
+
+@end
+
+@interface CDVFilesystemURLProtocol : NSURLProtocol
+@end
+
+@protocol CDVFileSystem
+- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url;
+- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options;
+- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI;
+- (void)getMetadataForURL:(CDVFilesystemURL *)url callback:(void (^)(CDVPluginResult *))callback;
+- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options;
+- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI;
+- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI;
+- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI;
+- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos;
+- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend;
+- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject<CDVFileSystem> *)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;
+@end
@interface CDVFile : CDVPlugin {
NSString* appDocsPath;
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7bb39777/src/ios/CDVFile.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVFile.m b/src/ios/CDVFile.m
index 47f32a5..b09b5f3 100644
--- a/src/ios/CDVFile.m
+++ b/src/ios/CDVFile.m
@@ -17,13 +17,10 @@
under the License.
*/
-#import "CDVFile.h"
#import <Cordova/CDV.h>
-#import <AssetsLibrary/ALAsset.h>
-#import <AssetsLibrary/ALAssetRepresentation.h>
-#import <AssetsLibrary/ALAssetsLibrary.h>
-#import <MobileCoreServices/MobileCoreServices.h>
-#import <sys/xattr.h>
+#import "CDVFile.h"
+#import "CDVLocalFilesystem.h"
+#import "CDVAssetLibraryFilesystem.h"
static CDVFile *filePlugin = nil;
@@ -33,24 +30,6 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import)
NSString* const NSURLIsExcludedFromBackupKey = @"NSURLIsExcludedFromBackupKey";
#endif
-NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
-NSString* const kCDVAssetsLibraryScheme = @"assets-library";
-
-@interface CDVFilesystemURL : NSObject {
- NSURL *_url;
- CDVFileSystemType _fileSystemType;
- NSString *_fullPath;
-}
-
-- (id) initWithString:(NSString*)strURL;
-- (id) initWithURL:(NSURL*)URL;
-
-@property (atomic) NSURL *url;
-@property (atomic) CDVFileSystemType fileSystemType;
-@property (atomic) NSString *fullPath;
-
-@end
-
@implementation CDVFilesystemURL
@synthesize url=_url;
@synthesize fileSystemType=_fileSystemType;
@@ -125,857 +104,6 @@ NSString* const kCDVAssetsLibraryScheme = @"assets-library";
@end
-@protocol CDVFileSystem
-- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url;
-- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options;
-- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI;
-- (void)getMetadataForURL:(CDVFilesystemURL *)url callback:(void (^)(CDVPluginResult *))callback;
-- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options;
-- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI;
-- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI;
-- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI;
-- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos;
-- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend;
-- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject<CDVFileSystem> *)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;
-@end
-
-@interface CDVLocalFilesystem : NSObject<CDVFileSystem> {
- NSString *_fsRoot;
-}
-- (id) initWithName:(NSString *)name root:(NSString *)fsRoot;
-@property (nonatomic,strong) NSString *fsRoot;
-@end
-
-@implementation CDVLocalFilesystem
-@synthesize fsRoot=_fsRoot;
-
-- (id) initWithName:(NSString *)name root:(NSString *)fsRoot
-{
- if (self) {
- _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;
- 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) {
- NSDictionary* fileSystem = [self makeEntryForPath:url.fullPath fileSystem:url.fileSystemType isDirectory:isDir];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
- } else {
- // return NOT_FOUND_ERR
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- }
- return result;
-}
-- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystem:(int)fsType isDirectory:(BOOL)isDir
-{
- NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5];
- NSString* lastPart = [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: [NSNumber numberWithInt:fsType] forKey: @"filesystem"];
-
- return dirEntry;
-}
-
-/*
- * 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
-{
- NSString *path = nil;
- NSString *fullPath = url.fullPath;
- path = [NSString stringWithFormat:@"%@%@", self.fsRoot, fullPath];
- if ([path hasSuffix:@"/"]) {
- path = [path substringToIndex:([path length]-1)];
- }
- return path;
-}
-
-
-- (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 ([options valueForKeyIsNumber:@"create"]) {
- create = [(NSNumber*)[options valueForKey:@"create"] boolValue];
- }
- if ([options valueForKeyIsNumber:@"exclusive"]) {
- exclusive = [(NSNumber*)[options valueForKey:@"exclusive"] boolValue];
- }
-
- if ([options valueForKeyIsNumber:@"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 {
- CDVFilesystemURL* requestedURL = [CDVFilesystemURL fileSystemURLWithURL:[NSURL URLWithString:[requestedPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] relativeToURL:baseURI.url]]; /* TODO: UGLY - FIX */
-
- // NSLog(@"reqFullPath = %@", reqFullPath);
- 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 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 fileSystem:baseURI.fileSystemType 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 fileSystem:newURI.fileSystemType isDirectory:bIsDir]];
- } else {
- // invalid path or file does not exist
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- }
- return result;
-}
-
-- (void)getMetadataForURL:(CDVFilesystemURL *)url callback:(void (^)(CDVPluginResult *))callback
-{
-
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- NSError* __autoreleasing error = nil;
-
- CDVPluginResult *result;
- NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:[self fileSystemPathForURL:url] error:&error];
-
- if (fileAttribs) {
- NSDate* modDate = [fileAttribs fileModificationDate];
- if (modDate) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[modDate timeIntervalSince1970] * 1000];
- }
- } else {
- // didn't get fileAttribs
- CDVFileError errorCode = ABORT_ERR;
- NSLog(@"error getting metadata: %@", [error localizedDescription]);
- if ([error code] == NSFileNoSuchFileError) {
- errorCode = NOT_FOUND_ERR;
- }
- // log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode];
- }
- if (!result) {
- // invalid path or file does not exist
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION];
- }
- callback(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]]) {
- 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] fileSystem:localURI.fileSystemType 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: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];
- [fileStream open];
-
- bytesWritten = [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<CDVFileSystem> *)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 = [self 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 fileSystem:srcURL.fileSystemType isDirectory:bSrcIsDir]; // should be the same type as source
- 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 fileSystem:destURL.fileSystemType 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";
- }
- }
- 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];
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- BOOL bIsDir = NO;
- // make sure it exists and is not a directory
- BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory:&bIsDir];
- if (!bExists || bIsDir) {
- callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]);
- } else {
- // create dictionary of file info
- NSError* __autoreleasing error = nil;
- NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:path error:&error];
- NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
- [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"];
- [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"];
- NSDate* modDate = [fileAttrs fileModificationDate];
- NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000];
- [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
- callback([CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]);
- }
-}
-
-@end
-
-@interface CDVAssetLibraryFilesystem : NSObject<CDVFileSystem> {
-}
-@end
-
-@implementation CDVAssetLibraryFilesystem
-- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url
-{
- NSDictionary* fileSystem = [self makeEntryForPath:[url.url absoluteString] fileSystem:ASSETS_LIBRARY isDirectory:NO];
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
-}
-
-- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystem:(int)fsType isDirectory:(BOOL)isDir
-{
- NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5];
- NSString* lastPart = [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: [NSNumber numberWithInt:fsType] forKey: @"filesystem"];
-
- return dirEntry;
-}
-
-- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options
-{
- // return unsupported result for assets-library URLs
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFile not supported for assets-library URLs."];
-}
-
-- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI
-{
- // we don't (yet?) support getting the parent of an asset
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
-}
-
-- (void)getMetadataForURL:(CDVFilesystemURL *)url callback:(void (^)(CDVPluginResult *))callback
-{
- __block CDVPluginResult* result = nil;
-
- // In this case, we need to use an asynchronous method to retrieve the file.
- // Because of this, we can't just assign to `result` and send it at the end of the method.
- // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
- ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
- if (asset) {
- // We have the asset! Retrieve the metadata and send it off.
- NSDate* date = [asset valueForProperty:ALAssetPropertyDate];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[date timeIntervalSince1970] * 1000];
- callback(result);
- } else {
- // We couldn't find the asset. Send the appropriate error.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- callback(result);
- }
- };
- // TODO(maxw): Consider making this a class variable since it's the same every time.
- ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
- // Retrieving the asset failed for some reason. Send the appropriate error.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
- callback(result);
- };
-
- ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
- [assetsLibrary assetForURL:url.url resultBlock:resultBlock failureBlock:failureBlock];
- return;
-}
-
-- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options
-{
- // setMetadata doesn't make sense for asset library files
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
-}
-
-- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI
-{
- // return error for assets-library URLs
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
-}
-
-- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI
-{
- // return error for assets-library URLs
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"removeRecursively not supported for assets-library URLs."];
-}
-
-- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI
-{
- // return unsupported result for assets-library URLs
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readEntries not supported for assets-library URLs."];
-}
-
-- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos
-{
- // assets-library files can't be truncated
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
-}
-
-- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend
-{
- // text can't be written into assets-library files
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
-}
-
-- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject<CDVFileSystem> *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback
-{
- // Copying to an assets library file is not doable, since we can't write it.
- CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
- callback(result);
-}
-
-- (NSString *)fileSystemPathForURL:(CDVFilesystemURL *)url
-{
- NSString *path = nil;
- if ([[url.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
- path = [url.url path];
- } else {
- path = url.fullPath;
- }
- if ([path hasSuffix:@"/"]) {
- path = [path substringToIndex:([path length]-1)];
- }
- return path;
-}
-
-- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback
-{
- NSString *path = [self fileSystemPathForURL:localURL];
-
- ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
- if (asset) {
- // We have the asset! Get the data and send it off.
- ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
- Byte* buffer = (Byte*)malloc([assetRepresentation size]);
- NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
- NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
- NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType);
-
- callback(data, MIMEType, NO_ERROR);
- } else {
- callback(nil, nil, NOT_FOUND_ERR);
- }
- };
-
- ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
- // Retrieving the asset failed for some reason. Send the appropriate error.
- NSLog(@"Error: %@", error);
- callback(nil, nil, SECURITY_ERR);
- };
-
- ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
- [assetsLibrary assetForURL:[NSURL URLWithString:path] resultBlock:resultBlock failureBlock:failureBlock];
-}
-
-- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback
-{
- NSString *path = [self fileSystemPathForURL:localURL];
-
- // In this case, we need to use an asynchronous method to retrieve the file.
- // Because of this, we can't just assign to `result` and send it at the end of the method.
- // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
- ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
- if (asset) {
- // We have the asset! Populate the dictionary and send it off.
- NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
- ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
- [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"];
- [fileInfo setObject:localURL.fullPath forKey:@"fullPath"];
- NSString* filename = [assetRepresentation filename];
- [fileInfo setObject:filename forKey:@"name"];
- [fileInfo setObject:[CDVLocalFilesystem getMimeTypeFromPath:filename] forKey:@"type"];
- NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate];
- NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000];
- [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
-
- callback([CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]);
- } else {
- // We couldn't find the asset. Send the appropriate error.
- callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]);
- }
- };
- ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
- // Retrieving the asset failed for some reason. Send the appropriate error.
- callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]);
- };
-
- ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
- [assetsLibrary assetForURL:[NSURL URLWithString:path] resultBlock:resultBlock failureBlock:failureBlock];
- return;
-}
-@end
-
-@interface CDVFilesystemURLProtocol : NSURLProtocol
-@end
-
@implementation CDVFilesystemURLProtocol
NSString* const kCDVFilesystemURLPrefix = @"filesystem";
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7bb39777/src/ios/CDVLocalFilesystem.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVLocalFilesystem.h b/src/ios/CDVLocalFilesystem.h
new file mode 100644
index 0000000..704dad8
--- /dev/null
+++ b/src/ios/CDVLocalFilesystem.h
@@ -0,0 +1,30 @@
+/*
+ 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<CDVFileSystem> {
+ NSString *_fsRoot;
+}
+
+- (id) initWithName:(NSString *)name root:(NSString *)fsRoot;
+
+@property (nonatomic,strong) NSString *fsRoot;
+
+@end
[3/6] CB-5406: Factor out filesystem providers in iOS
Posted by ia...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/64187ca1/src/ios/CDVFile.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVFile.m b/src/ios/CDVFile.m
index 29a3241..47f32a5 100644
--- a/src/ios/CDVFile.m
+++ b/src/ios/CDVFile.m
@@ -27,51 +27,951 @@
static CDVFile *filePlugin = nil;
+extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import));
+
+#ifndef __IPHONE_5_1
+ NSString* const NSURLIsExcludedFromBackupKey = @"NSURLIsExcludedFromBackupKey";
+#endif
+
+NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
+NSString* const kCDVAssetsLibraryScheme = @"assets-library";
+
@interface CDVFilesystemURL : NSObject {
- NSURL *url_;
- CDVFileSystemType fileSystemType_;
- NSString *fullPath_;
- NSString *fileSystemPath_;
+ NSURL *_url;
+ CDVFileSystemType _fileSystemType;
+ NSString *_fullPath;
+}
+
+- (id) initWithString:(NSString*)strURL;
+- (id) initWithURL:(NSURL*)URL;
+
+@property (atomic) NSURL *url;
+@property (atomic) CDVFileSystemType fileSystemType;
+@property (atomic) NSString *fullPath;
+
+@end
+
+@implementation CDVFilesystemURL
+@synthesize url=_url;
+@synthesize fileSystemType=_fileSystemType;
+@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;
+ _fileSystemType = [self filesystemTypeForLocalURI:URL];
+ _fullPath = [self fullPathForLocalURI:URL];
+ }
+ return self;
+}
+
+/*
+ * IN
+ * NSString localURI
+ * OUT
+ * int FileSystem type for this URI, or -1 if it is not recognized.
+ */
+- (CDVFileSystemType)filesystemTypeForLocalURI:(NSURL *)uri
+{
+ if ([[uri scheme] isEqualToString:@"filesystem"] && [[uri host] isEqualToString:@"localhost"]) {
+ if ([[uri path] hasPrefix:@"/temporary"]) {
+ return TEMPORARY;
+ } else if ([[uri path] hasPrefix:@"/persistent"]) {
+ return PERSISTENT;
+ }
+ } else if ([[uri scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
+ return ASSETS_LIBRARY;
+ }
+ return -1;
+}
+
+/*
+ * 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
+{
+ int fsType = [self filesystemTypeForLocalURI:uri];
+ if (fsType == TEMPORARY) {
+ return [[uri path] substringFromIndex:10];
+ } else if (fsType == PERSISTENT) {
+ return [[uri path] substringFromIndex:11];
+ }
+ return nil;
+}
+
++ (CDVFilesystemURL *)fileSystemURLWithString:(NSString *)strURL
+{
+ return [[CDVFilesystemURL alloc] initWithString:strURL];
+}
+
++ (CDVFilesystemURL *)fileSystemURLWithURL:(NSURL *)URL
+{
+ return [[CDVFilesystemURL alloc] initWithURL:URL];
+}
+
+@end
+
+@protocol CDVFileSystem
+- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url;
+- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options;
+- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI;
+- (void)getMetadataForURL:(CDVFilesystemURL *)url callback:(void (^)(CDVPluginResult *))callback;
+- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options;
+- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI;
+- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI;
+- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI;
+- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos;
+- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend;
+- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject<CDVFileSystem> *)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;
+@end
+
+@interface CDVLocalFilesystem : NSObject<CDVFileSystem> {
+ NSString *_fsRoot;
+}
+- (id) initWithName:(NSString *)name root:(NSString *)fsRoot;
+@property (nonatomic,strong) NSString *fsRoot;
+@end
+
+@implementation CDVLocalFilesystem
+@synthesize fsRoot=_fsRoot;
+
+- (id) initWithName:(NSString *)name root:(NSString *)fsRoot
+{
+ if (self) {
+ _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;
+ 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) {
+ NSDictionary* fileSystem = [self makeEntryForPath:url.fullPath fileSystem:url.fileSystemType isDirectory:isDir];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
+ } else {
+ // return NOT_FOUND_ERR
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+ }
+ return result;
+}
+- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystem:(int)fsType isDirectory:(BOOL)isDir
+{
+ NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5];
+ NSString* lastPart = [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: [NSNumber numberWithInt:fsType] forKey: @"filesystem"];
+
+ return dirEntry;
+}
+
+/*
+ * 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
+{
+ NSString *path = nil;
+ NSString *fullPath = url.fullPath;
+ path = [NSString stringWithFormat:@"%@%@", self.fsRoot, fullPath];
+ if ([path hasSuffix:@"/"]) {
+ path = [path substringToIndex:([path length]-1)];
+ }
+ return path;
+}
+
+
+- (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 ([options valueForKeyIsNumber:@"create"]) {
+ create = [(NSNumber*)[options valueForKey:@"create"] boolValue];
+ }
+ if ([options valueForKeyIsNumber:@"exclusive"]) {
+ exclusive = [(NSNumber*)[options valueForKey:@"exclusive"] boolValue];
+ }
+
+ if ([options valueForKeyIsNumber:@"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 {
+ CDVFilesystemURL* requestedURL = [CDVFilesystemURL fileSystemURLWithURL:[NSURL URLWithString:[requestedPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] relativeToURL:baseURI.url]]; /* TODO: UGLY - FIX */
+
+ // NSLog(@"reqFullPath = %@", reqFullPath);
+ 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 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 fileSystem:baseURI.fileSystemType 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 fileSystem:newURI.fileSystemType isDirectory:bIsDir]];
+ } else {
+ // invalid path or file does not exist
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+ }
+ return result;
+}
+
+- (void)getMetadataForURL:(CDVFilesystemURL *)url callback:(void (^)(CDVPluginResult *))callback
+{
+
+ NSFileManager* fileMgr = [[NSFileManager alloc] init];
+ NSError* __autoreleasing error = nil;
+
+ CDVPluginResult *result;
+ NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:[self fileSystemPathForURL:url] error:&error];
+
+ if (fileAttribs) {
+ NSDate* modDate = [fileAttribs fileModificationDate];
+ if (modDate) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[modDate timeIntervalSince1970] * 1000];
+ }
+ } else {
+ // didn't get fileAttribs
+ CDVFileError errorCode = ABORT_ERR;
+ NSLog(@"error getting metadata: %@", [error localizedDescription]);
+ if ([error code] == NSFileNoSuchFileError) {
+ errorCode = NOT_FOUND_ERR;
+ }
+ // log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode];
+ }
+ if (!result) {
+ // invalid path or file does not exist
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION];
+ }
+ callback(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]]) {
+ 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] fileSystem:localURI.fileSystemType 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: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];
+ [fileStream open];
+
+ bytesWritten = [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<CDVFileSystem> *)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 = [self 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 fileSystem:srcURL.fileSystemType isDirectory:bSrcIsDir]; // should be the same type as source
+ 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 fileSystem:destURL.fileSystemType 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);
}
-- (id) initWithString:(NSString*)strURL;
-- (id) initWithURL:(NSURL*)URL;
+/* 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;
-@property (atomic) NSURL *url;
-@property (atomic) CDVFileSystemType fileSystemType;
-@property (atomic) NSString *fullPath;
-@property (atomic) NSString *fileSystemPath;
+ 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";
+ }
+ }
+ 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];
+ NSFileManager* fileMgr = [[NSFileManager alloc] init];
+ BOOL bIsDir = NO;
+ // make sure it exists and is not a directory
+ BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory:&bIsDir];
+ if (!bExists || bIsDir) {
+ callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]);
+ } else {
+ // create dictionary of file info
+ NSError* __autoreleasing error = nil;
+ NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:path error:&error];
+ NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
+ [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"];
+ [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"];
+ NSDate* modDate = [fileAttrs fileModificationDate];
+ NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000];
+ [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
+ callback([CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]);
+ }
+}
@end
-@implementation CDVFilesystemURL
-@synthesize url=url_;
-@synthesize fileSystemType=fileSystemType_;
-@synthesize fullPath=fullPath_, fileSystemPath=fileSystemPath_;
+@interface CDVAssetLibraryFilesystem : NSObject<CDVFileSystem> {
+}
+@end
-- (id) initWithString:(NSString *)strURL
+@implementation CDVAssetLibraryFilesystem
+- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url
{
- NSURL *decodedURL = [NSURL URLWithString:strURL];
- return [self initWithURL:decodedURL];
+ NSDictionary* fileSystem = [self makeEntryForPath:[url.url absoluteString] fileSystem:ASSETS_LIBRARY isDirectory:NO];
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
}
--(id) initWithURL:(NSURL *)URL
+- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystem:(int)fsType isDirectory:(BOOL)isDir
{
- url_ = URL;
- fileSystemType_ = -42;
- return self;
+ NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5];
+ NSString* lastPart = [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: [NSNumber numberWithInt:fsType] forKey: @"filesystem"];
+
+ return dirEntry;
}
-@end
+- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options
+{
+ // return unsupported result for assets-library URLs
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFile not supported for assets-library URLs."];
+}
-extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import));
+- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI
+{
+ // we don't (yet?) support getting the parent of an asset
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
+}
-#ifndef __IPHONE_5_1
- NSString* const NSURLIsExcludedFromBackupKey = @"NSURLIsExcludedFromBackupKey";
-#endif
+- (void)getMetadataForURL:(CDVFilesystemURL *)url callback:(void (^)(CDVPluginResult *))callback
+{
+ __block CDVPluginResult* result = nil;
-NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
-NSString* const kCDVAssetsLibraryScheme = @"assets-library";
+ // In this case, we need to use an asynchronous method to retrieve the file.
+ // Because of this, we can't just assign to `result` and send it at the end of the method.
+ // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
+ ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
+ if (asset) {
+ // We have the asset! Retrieve the metadata and send it off.
+ NSDate* date = [asset valueForProperty:ALAssetPropertyDate];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[date timeIntervalSince1970] * 1000];
+ callback(result);
+ } else {
+ // We couldn't find the asset. Send the appropriate error.
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+ callback(result);
+ }
+ };
+ // TODO(maxw): Consider making this a class variable since it's the same every time.
+ ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
+ // Retrieving the asset failed for some reason. Send the appropriate error.
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
+ callback(result);
+ };
+
+ ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+ [assetsLibrary assetForURL:url.url resultBlock:resultBlock failureBlock:failureBlock];
+ return;
+}
+
+- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options
+{
+ // setMetadata doesn't make sense for asset library files
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
+}
+
+- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI
+{
+ // return error for assets-library URLs
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
+}
+
+- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI
+{
+ // return error for assets-library URLs
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"removeRecursively not supported for assets-library URLs."];
+}
+
+- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI
+{
+ // return unsupported result for assets-library URLs
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readEntries not supported for assets-library URLs."];
+}
+
+- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos
+{
+ // assets-library files can't be truncated
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
+}
+
+- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend
+{
+ // text can't be written into assets-library files
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
+}
+
+- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject<CDVFileSystem> *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback
+{
+ // Copying to an assets library file is not doable, since we can't write it.
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
+ callback(result);
+}
+
+- (NSString *)fileSystemPathForURL:(CDVFilesystemURL *)url
+{
+ NSString *path = nil;
+ if ([[url.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
+ path = [url.url path];
+ } else {
+ path = url.fullPath;
+ }
+ if ([path hasSuffix:@"/"]) {
+ path = [path substringToIndex:([path length]-1)];
+ }
+ return path;
+}
+
+- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback
+{
+ NSString *path = [self fileSystemPathForURL:localURL];
+
+ ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
+ if (asset) {
+ // We have the asset! Get the data and send it off.
+ ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
+ Byte* buffer = (Byte*)malloc([assetRepresentation size]);
+ NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
+ NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
+ NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType);
+
+ callback(data, MIMEType, NO_ERROR);
+ } else {
+ callback(nil, nil, NOT_FOUND_ERR);
+ }
+ };
+
+ ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
+ // Retrieving the asset failed for some reason. Send the appropriate error.
+ NSLog(@"Error: %@", error);
+ callback(nil, nil, SECURITY_ERR);
+ };
+
+ ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+ [assetsLibrary assetForURL:[NSURL URLWithString:path] resultBlock:resultBlock failureBlock:failureBlock];
+}
+
+- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback
+{
+ NSString *path = [self fileSystemPathForURL:localURL];
+
+ // In this case, we need to use an asynchronous method to retrieve the file.
+ // Because of this, we can't just assign to `result` and send it at the end of the method.
+ // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
+ ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
+ if (asset) {
+ // We have the asset! Populate the dictionary and send it off.
+ NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
+ ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
+ [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"];
+ [fileInfo setObject:localURL.fullPath forKey:@"fullPath"];
+ NSString* filename = [assetRepresentation filename];
+ [fileInfo setObject:filename forKey:@"name"];
+ [fileInfo setObject:[CDVLocalFilesystem getMimeTypeFromPath:filename] forKey:@"type"];
+ NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate];
+ NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000];
+ [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
+
+ callback([CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]);
+ } else {
+ // We couldn't find the asset. Send the appropriate error.
+ callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]);
+ }
+ };
+ ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
+ // Retrieving the asset failed for some reason. Send the appropriate error.
+ callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]);
+ };
+
+ ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+ [assetsLibrary assetForURL:[NSURL URLWithString:path] resultBlock:resultBlock failureBlock:failureBlock];
+ return;
+}
+@end
@interface CDVFilesystemURLProtocol : NSURLProtocol
@end
@@ -98,17 +998,16 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
- (void)startLoading
{
- NSURL *url = [[self request] URL];
- NSString *pathString = [url relativePath];
- pathString = [filePlugin fileSystemPathForLocalURI:url];
- [CDVFile readFileWithPath:pathString start:0 end:-1 callback:^void(NSData *data, NSString *mimetype, CDVFileError error) {
+ CDVFilesystemURL* url = [CDVFilesystemURL fileSystemURLWithURL:[[self request] URL]];
+ CDVLocalFilesystem *fs = [filePlugin.fileSystems objectAtIndex:url.fileSystemType];
+ [fs readFileAtURL:url start:0 end:-1 callback:^void(NSData *data, NSString *mimetype, CDVFileError error) {
if (!error) {
- NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url statusCode:200 HTTPVersion:@"HTTP/1.1"headerFields:@{@"Content-Type": mimetype}];
+ NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url.url statusCode:200 HTTPVersion:@"HTTP/1.1"headerFields:@{@"Content-Type": mimetype}];
[[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 statusCode:404 HTTPVersion:@"HTTP/1.1"headerFields:@{}];
+ NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url.url statusCode:404 HTTPVersion:@"HTTP/1.1"headerFields:@{}];
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocolDidFinishLoading:self];
}
@@ -125,7 +1024,7 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
@implementation CDVFile
-@synthesize appDocsPath, appLibraryPath, appTempPath, persistentPath, temporaryPath, userHasAllowed;
+@synthesize appDocsPath, appLibraryPath, appTempPath, persistentPath, temporaryPath, userHasAllowed, fileSystems=fileSystems_;
- (id)initWithWebView:(UIWebView*)theWebView
{
@@ -134,15 +1033,22 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
filePlugin = self;
[NSURLProtocol registerClass:[CDVFilesystemURLProtocol class]];
- // get the documents directory path
- NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- self.appDocsPath = [paths objectAtIndex:0];
+ fileSystems_ = [[NSMutableArray alloc] initWithCapacity:3];
- paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
+ // get the temporary directory path
+ NSArray* paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
self.appLibraryPath = [paths objectAtIndex:0];
self.appTempPath = [NSTemporaryDirectory()stringByStandardizingPath]; // remove trailing slash from NSTemporaryDirectory()
+ [fileSystems_ addObject:[[CDVLocalFilesystem alloc] initWithName:@"temporary" root:[paths objectAtIndex:0]]];
+
+ // get the documents directory path
+ paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ self.appDocsPath = [paths objectAtIndex:0];
+
+ [fileSystems_ addObject:[[CDVLocalFilesystem alloc] initWithName:@"persistent" root:[paths objectAtIndex:0]]];
+
self.persistentPath = [NSString stringWithFormat:@"/%@", [self.appDocsPath lastPathComponent]];
self.temporaryPath = [NSString stringWithFormat:@"/%@", [self.appTempPath lastPathComponent]];
// NSLog(@"docs: %@ - temp: %@", self.appDocsPath, self.appTempPath);
@@ -151,115 +1057,6 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
return self;
}
-- (void)updateFileSystemURL:(CDVFilesystemURL *)fsURL;
-{
- fsURL.fileSystemType = [self filesystemTypeForLocalURI:fsURL.url];
- fsURL.fileSystemPath = [self fileSystemPathForLocalURI:fsURL.url];
- fsURL.fullPath = [self fullPathForFileSystemPath:fsURL.fileSystemPath];
-}
-
-- (CDVFilesystemURL *)fileSystemURLWithString:(NSString *)strURL
-{
- CDVFilesystemURL* fsURL = [[CDVFilesystemURL alloc] initWithString:strURL];
- if (fsURL) {
- [self updateFileSystemURL:fsURL];
- }
- return fsURL;
-}
-
-- (CDVFilesystemURL *)fileSystemURLWithURL:(NSURL *)URL
-{
- CDVFilesystemURL* fsURL = [[CDVFilesystemURL alloc] initWithURL:URL];
- if (fsURL) {
- [self updateFileSystemURL:fsURL];
- }
- return fsURL;
-}
-
-/*
- * 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 *)fileSystemPathForLocalURI:(NSURL *)uri
-{
- NSString *path = nil;
- int fsType = [self filesystemTypeForLocalURI:uri];
- NSString *fullPath = [self fullPathForLocalURI:uri];
- if (fsType == TEMPORARY) {
- path = [NSString stringWithFormat:@"%@%@", self.appTempPath, fullPath];
- } else if (fsType == PERSISTENT) {
- path = [NSString stringWithFormat:@"%@%@", self.appDocsPath, fullPath];
- } else {
- return nil;
- }
- if ([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 *)fullPathForFileSystemPath:(NSString *)fsPath
-{
- if ([fsPath hasPrefix:self.appTempPath]) {
- return [fsPath substringFromIndex:[self.appTempPath length]];
- } else if ([fsPath hasPrefix:self.appDocsPath]) {
- return [fsPath substringFromIndex:[self.appDocsPath length]];
- }
- 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
-{
- int fsType = [self filesystemTypeForLocalURI:uri];
- if (fsType == TEMPORARY) {
- return [[uri path] substringFromIndex:10];
- } else if (fsType == PERSISTENT) {
- return [[uri path] substringFromIndex:11];
- }
- return nil;
-}
-
-/*
- * IN
- * NSString localURI
- * OUT
- * int FileSystem type for this URI, or -1 if it is not recognized.
- */
-- (CDVFileSystemType)filesystemTypeForLocalURI:(NSURL *)uri
-{
- if ([[uri scheme] isEqualToString:@"filesystem"] && [[uri host] isEqualToString:@"localhost"]) {
- if ([[uri path] hasPrefix:@"/temporary"]) {
- return TEMPORARY;
- } else if ([[uri path] hasPrefix:@"/persistent"]) {
- return PERSISTENT;
- }
- }
- return -1;
-}
-
- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath
{
@@ -269,32 +1066,8 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
NSDictionary* pDict = [fMgr attributesOfFileSystemForPath:appPath error:&pError];
NSNumber* pNumAvail = (NSNumber*)[pDict objectForKey:NSFileSystemFreeSize];
-
- return pNumAvail;
-}
-
-// figure out if the (device local file sytstem) pathFragment represents a persistent or temporary directory
-// and return the full application path.
-// returns nil if path is not persistent or temporary
-- (NSString*)getAppPath:(NSString*)pathFragment
-{
- NSString* appPath = nil;
- NSRange rangeP = [pathFragment rangeOfString:self.persistentPath];
- NSRange rangeT = [pathFragment rangeOfString:self.temporaryPath];
-
- if ((rangeP.location != NSNotFound) && (rangeT.location != NSNotFound)) {
- // we found both in the path, return whichever one is first
- if (rangeP.length < rangeT.length) {
- appPath = self.appDocsPath;
- } else {
- appPath = self.appTempPath;
- }
- } else if (rangeP.location != NSNotFound) {
- appPath = self.appDocsPath;
- } else if (rangeT.location != NSNotFound) {
- appPath = self.appTempPath;
- }
- return appPath;
+
+ return pNumAvail;
}
/* Request the File System info
@@ -378,12 +1151,6 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
return dirEntry;
}
-/* STRONGLY DEPRECATED */
-- (NSDictionary*)getDirectoryEntry:(NSString*)fullPath isDirectory:(BOOL)isDir
-{
- return [self makeEntryForPath:fullPath fileSystem:42 isDirectory:isDir];
-}
-
/*
* Given a URI determine the File System information associated with it and return an appropriate W3C entry object
* IN
@@ -399,46 +1166,18 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command
{
// arguments
- CDVFilesystemURL* inputUri = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
- CDVPluginResult* result = [self entryForLocalURI:inputUri];
- if (result != nil) {
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- }
-}
-
-/*
- * 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;
- if ([[url.url scheme] isEqualToString:@"assets-library"]) {
- NSDictionary* fileSystem = [self getDirectoryEntry:[url.url absoluteString] isDirectory:NO];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
+ CDVFilesystemURL* inputURI = [CDVFilesystemURL fileSystemURLWithString:[command.arguments objectAtIndex:0]];
+ CDVPluginResult* result;
+ if (inputURI.fileSystemType == -1) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR];
} else {
- if (url.fileSystemType == -1) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR];
- } else {
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- BOOL isDir = NO;
- // see if exists and is file or dir
- BOOL bExists = [fileMgr fileExistsAtPath:url.fileSystemPath isDirectory:&isDir];
- if (bExists) {
- NSDictionary* fileSystem = [self makeEntryForPath:url.fullPath fileSystem:url.fileSystemType isDirectory:isDir];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
- } else {
- // return NOT_FOUND_ERR
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- }
- }
+ CDVLocalFilesystem *fs = [self.fileSystems objectAtIndex:inputURI.fileSystemType];
+ result = [fs entryForLocalURI:inputURI];
}
- return result;
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
+
/* Part of DirectoryEntry interface, creates or returns the specified directory
* IN:
* NSString* localURI - local filesystem URI for this directory
@@ -499,85 +1238,13 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
- (void)getFile:(CDVInvokedUrlCommand*)command
{
NSString* baseURIstr = [command.arguments objectAtIndex:0];
- CDVFilesystemURL* baseURI = [self fileSystemURLWithString:baseURIstr];
+ CDVFilesystemURL* baseURI = [CDVFilesystemURL fileSystemURLWithString:baseURIstr];
NSString* requestedPath = [command.arguments objectAtIndex:1];
NSDictionary* options = [command.arguments objectAtIndex:2 withDefault:nil];
- // return unsupported result for assets-library URLs
- if ([[baseURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
- CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFile not supported for assets-library URLs."];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- return;
- }
-
- CDVPluginResult* result = nil;
- BOOL bDirRequest = NO;
- BOOL create = NO;
- BOOL exclusive = NO;
- int errorCode = 0; // !!! risky - no error code currently defined for 0
-
- if ([options valueForKeyIsNumber:@"create"]) {
- create = [(NSNumber*)[options valueForKey:@"create"] boolValue];
- }
- if ([options valueForKeyIsNumber:@"exclusive"]) {
- exclusive = [(NSNumber*)[options valueForKey:@"exclusive"] boolValue];
- }
-
- if ([options valueForKeyIsNumber:@"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 {
- CDVFilesystemURL* requestedURL = [self fileSystemURLWithURL:[NSURL URLWithString:[requestedPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] relativeToURL:baseURI.url]]; /* TODO: UGLY - FIX */
-
- // NSLog(@"reqFullPath = %@", reqFullPath);
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- BOOL bIsDir;
- BOOL bExists = [fileMgr fileExistsAtPath:requestedURL.fileSystemPath isDirectory:&bIsDir];
- if (bExists && (create == NO) && (bIsDir == !bDirRequest)) {
- // path exists and is 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:requestedURL.fileSystemPath withIntermediateDirectories:NO attributes:nil error:&pError];
- } else {
- // create the empty file
- bSuccess = [fileMgr createFileAtPath:requestedURL.fileSystemPath 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 fileSystem:baseURI.fileSystemType isDirectory:bDirRequest]];
- }
- } // are all possible conditions met?
- }
+ CDVLocalFilesystem *fs = [self.fileSystems objectAtIndex:baseURI.fileSystemType];
+ CDVPluginResult* result = [fs getFileForURL:baseURI requestedPath:requestedPath options:options];
- if (errorCode > 0) {
- // create error callback
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
- }
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
@@ -594,32 +1261,11 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
- (void)getParent:(CDVInvokedUrlCommand*)command
{
// arguments are URL encoded
- CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
+ CDVFilesystemURL* localURI = [CDVFilesystemURL fileSystemURLWithString:[command.arguments objectAtIndex:0]];
- // we don't (yet?) support getting the parent of an asset
- if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
- CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- return;
- }
+ CDVLocalFilesystem *fs = [self.fileSystems objectAtIndex:localURI.fileSystemType];
+ CDVPluginResult* result = [fs getParentForURL:localURI];
- CDVPluginResult* result = nil;
- CDVFilesystemURL *newURI = nil;
- if ([localURI.fullPath isEqualToString:@""]) {
- // return self
- newURI = localURI;
- } else {
- newURI = [self fileSystemURLWithURL:[localURI.url URLByDeletingLastPathComponent]]; /* TODO: UGLY - FIX */
- }
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- BOOL bIsDir;
- BOOL bExists = [fileMgr fileExistsAtPath:newURI.fileSystemPath isDirectory:&bIsDir];
- if (bExists) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:newURI.fullPath fileSystem:newURI.fileSystemType isDirectory:bIsDir]];
- } else {
- // invalid path or file does not exist
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- }
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
@@ -631,63 +1277,12 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
{
// arguments
NSString* localURIstr = [command.arguments objectAtIndex:0];
- CDVFilesystemURL* localURI = [self fileSystemURLWithString:localURIstr];
-
- __block CDVPluginResult* result = nil;
-
- if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
- // In this case, we need to use an asynchronous method to retrieve the file.
- // Because of this, we can't just assign to `result` and send it at the end of the method.
- // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
- ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
- if (asset) {
- // We have the asset! Retrieve the metadata and send it off.
- NSDate* date = [asset valueForProperty:ALAssetPropertyDate];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[date timeIntervalSince1970] * 1000];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- } else {
- // We couldn't find the asset. Send the appropriate error.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- }
- };
- // TODO(maxw): Consider making this a class variable since it's the same every time.
- ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
- // Retrieving the asset failed for some reason. Send the appropriate error.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- };
-
- ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
- [assetsLibrary assetForURL:[NSURL URLWithString:localURIstr] resultBlock:resultBlock failureBlock:failureBlock];
- return;
- }
-
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- NSError* __autoreleasing error = nil;
-
- NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:localURI.fileSystemPath error:&error];
+ CDVFilesystemURL* localURI = [CDVFilesystemURL fileSystemURLWithString:localURIstr];
+ CDVLocalFilesystem *fs = [self.fileSystems objectAtIndex:localURI.fileSystemType];
+ [fs getMetadataForURL:localURI callback:^(CDVPluginResult* result) {
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ }];
- if (fileAttribs) {
- NSDate* modDate = [fileAttribs fileModificationDate];
- if (modDate) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[modDate timeIntervalSince1970] * 1000];
- }
- } else {
- // didn't get fileAttribs
- CDVFileError errorCode = ABORT_ERR;
- NSLog(@"error getting metadata: %@", [error localizedDescription]);
- if ([error code] == NSFileNoSuchFileError) {
- errorCode = NOT_FOUND_ERR;
- }
- // log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode];
- }
- if (!result) {
- // invalid path or file does not exist
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION];
- }
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
/*
@@ -697,42 +1292,11 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
- (void)setMetadata:(CDVInvokedUrlCommand*)command
{
// arguments
- CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
+ CDVFilesystemURL* localURI = [CDVFilesystemURL fileSystemURLWithString:[command.arguments objectAtIndex:0]];
NSDictionary* options = [command.arguments objectAtIndex:1 withDefault:nil];
+ CDVLocalFilesystem *fs = [self.fileSystems objectAtIndex:localURI.fileSystemType];
+ CDVPluginResult* result = [fs setMetadataForURL:localURI withObject:options];
- CDVPluginResult* result = nil;
- BOOL ok = NO;
-
- // setMetadata doesn't make sense for asset library files
- if (![[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
- NSString* filePath = localURI.fileSystemPath;
- // 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]]) {
- 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) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
- } else {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
- }
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
@@ -748,33 +1312,15 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
- (void)remove:(CDVInvokedUrlCommand*)command
{
// arguments
- CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
+ CDVFilesystemURL* localURI = [CDVFilesystemURL fileSystemURLWithString:[command.arguments objectAtIndex:0]];
CDVPluginResult* result = nil;
- CDVFileError errorCode = 0; // !! 0 not currently defined
- // return error for assets-library URLs
- if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
- errorCode = INVALID_MODIFICATION_ERR;
- } else if ([localURI.fullPath isEqualToString:@""]) {
+ if ([localURI.fullPath isEqualToString:@""]) {
// error if try to remove top level (documents or tmp) dir
- errorCode = NO_MODIFICATION_ALLOWED_ERR;
- } else {
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- BOOL bIsDir = NO;
- BOOL bExists = [fileMgr fileExistsAtPath:localURI.fileSystemPath isDirectory:&bIsDir];
- if (!bExists) {
- errorCode = NOT_FOUND_ERR;
- }
- if (bIsDir && ([[fileMgr contentsOfDirectoryAtPath:localURI.fileSystemPath error:nil] count] != 0)) {
- // dir is not empty
- errorCode = INVALID_MODIFICATION_ERR;
- }
- }
- if (errorCode > 0) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
} else {
- // perform actual remove
- result = [self doRemove:localURI.fileSystemPath];
+ CDVLocalFilesystem *fs = [self.fileSystems objectAtIndex:localURI.fileSystemType];
+ result = [fs removeFileAtURL:localURI];
}
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
@@ -790,99 +1336,27 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
- (void)removeRecursively:(CDVInvokedUrlCommand*)command
{
// arguments
- CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
-
- // return unsupported result for assets-library URLs
- if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
- CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"removeRecursively not supported for assets-library URLs."];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- return;
- }
-
+ CDVFilesystemURL* localURI = [CDVFilesystemURL fileSystemURLWithString:[command.arguments objectAtIndex:0]];
CDVPluginResult* result = nil;
- // error if try to remove top level (documents or tmp) dir
+
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 {
- result = [self doRemove:localURI.fileSystemPath];
- }
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-}
-
-/* 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;
-}
-
-- (void)copyTo:(CDVInvokedUrlCommand*)command
-{
- [self doCopyMove:command isCopy:YES];
-}
-
-- (void)moveTo:(CDVInvokedUrlCommand*)command
-{
- [self doCopyMove:command isCopy:NO];
-}
-
-/**
- * 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;
- }
+ } else {
+ CDVLocalFilesystem *fs = [self.fileSystems objectAtIndex:localURI.fileSystemType];
+ result = [fs recursiveRemoveFileAtURL:localURI];
}
- return copyOK;
+ [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
@@ -901,329 +1375,57 @@ NSString* const kCDVFilesystemURLPrefix = @"filesystem";
NSString* srcURLstr = [arguments objectAtIndex:0];
NSString* destURLstr = [arguments objectAtIndex:1];
- __block CDVPluginResult* result = nil;
- CDVFileError errCode = 0; // !! Currently 0 is not defined, use this to signal error !!
+ CDVPluginResult *result;
if (!srcURLstr || !destURLstr) {
// either no source or no destination provided
- errCode = NOT_FOUND_ERR;
- } else {
- CDVFilesystemURL* srcURL = [self fileSystemURLWithString:srcURLstr];
- CDVFilesystemURL* destURL = [self fileSystemURLWithString:destURLstr];
- NSString* srcFullPath = srcURL.fileSystemPath;
- NSString* destRootPath = destURL.fileSystemPath;
-
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ return;
+ }
+
+ CDVFilesystemURL* srcURL = [CDVFilesystemURL fileSystemURLWithString:srcURLstr];
+ CDVFilesystemURL* destURL = [CDVFilesystemURL fileSystemURLWithString:destURLstr];
+
+ CDVLocalFilesystem *srcFs = [self.fileSystems objectAtIndex:srcURL.fileSystemType];
+ CDVLocalFilesystem *destFs = [self.fileSystems objectAtIndex:destURL.fileSystemType];
+
// optional argument; use last component from srcFullPath if new name not provided
- NSString* newName = ([arguments count] > 2) ? [arguments objectAtIndex:2] : [srcFullPath lastPathComponent];
+ NSString* newName = ([arguments count] > 2) ? [arguments objectAtIndex:2] : [srcURL.url lastPathComponent];
if ([newName rangeOfString:@":"].location != NSNotFound) {
// invalid chars in new name
- errCode = ENCODING_ERR;
- } else {
- NSString* newFileSystemPath = [destRootPath stringByAppendingPathComponent:newName];
- NSString* newFullPath = [self fullPathForFileSystemPath:newFileSystemPath];
-
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- if ([newFileSystemPath isEqualToString:srcFullPath]) {
- // source and destination can not be the same
- errCode = INVALID_MODIFICATION_ERR;
- } else if ([[srcURL.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
- if (bCopy) {
- // Copying (as opposed to moving) an assets library file is okay.
- // In this case, we need to use an asynchronous method to retrieve the file.
- // Because of this, we can't just assign to `result` and send it at the end of the method.
- // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
- ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
- if (asset) {
- // We have the asset! Get the data and try to copy it over.
- if (![fileMgr fileExistsAtPath:destRootPath]) {
- // The destination directory doesn't exist.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- return;
- } else if ([fileMgr fileExistsAtPath:newFileSystemPath]) {
- // A file already exists at the destination path.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:PATH_EXISTS_ERR];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- return;
- }
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR];
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ return;
+ }
- // We're good to go! Write the file to the new destination.
- ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
- Byte* buffer = (Byte*)malloc([assetRepresentation size]);
- NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
- NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
- [data writeToFile:newFileSystemPath atomically:YES];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:newFileSystemPath isDirectory:NO]];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- } else {
- // We couldn't find the asset. Send the appropriate error.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- }
- };
- ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
- // Retrieving the asset failed for some reason. Send the appropriate error.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- };
-
- ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
- [assetsLibrary assetForURL:[NSURL URLWithString:srcFullPath] resultBlock:resultBlock failureBlock:failureBlock];
- return;
- } else {
- // Moving an assets library file is not doable, since we can't remove it.
- errCode = INVALID_MODIFICATION_ERR;
- }
- } else {
- BOOL bSrcIsDir = NO;
- BOOL bDestIsDir = NO;
- BOOL bNewIsDir = NO;
- BOOL bSrcExists = [fileMgr fileExistsAtPath:srcFullPath isDirectory:&bSrcIsDir];
- BOOL bDestExists = [fileMgr fileExistsAtPath:destRootPath isDirectory:&bDestIsDir];
- BOOL bNewExists = [fileMgr fileExistsAtPath:newFileSystemPath isDirectory:&bNewIsDir];
- if (!bSrcExists || !bDestExists) {
- // the source or the destination root does not exist
- errCode = NOT_FOUND_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;
- }
+ [destFs copyFileToURL:destURL withName:newName fromFileSystem:srcFs atURL:srcURL copy:bCopy callback:^(CDVPluginResult* result) {
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ }];
- 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 fileSystem:srcURL.fileSystemType isDirectory:bSrcIsDir]; // should be the same type as source
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry];
- } else {
- errCode = INVALID_MODIFICATION_ERR; // catch all
- 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;
- }
- }
- }
- }
- }
- }
- }
- if (errCode > 0) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errCode];
- }
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
- (void)getFileMetadata:(CDVInvokedUrlCommand*)command
{
// arguments
NSString* localURIstr = [command.arguments objectAtIndex:0];
- CDVFilesystemURL* localURI = [self fileSystemURLWithString:localURIstr];
-
- __block CDVPluginResult* result = nil;
+ CDVFilesystemURL* localURI = [CDVFilesystemURL fileSystemURLWithString:localURIstr];
+ CDVLocalFilesystem *fs = [self.fileSystems objectAtIndex:localURI.fileSystemType];
- if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
- // In this case, we need to use an asynchronous method to retrieve the file.
- // Because of this, we can't just assign to `result` and send it at the end of the method.
- // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
- ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
- if (asset) {
- // We have the asset! Populate the dictionary and send it off.
- NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
- ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
- [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"];
- [fileInfo setObject:localURIstr forKey:@"fullPath"];
- NSString* filename = [assetRepresentation filename];
- [fileInfo setObject:filename forKey:@"name"];
- [fileInfo setObject:[self getMimeTypeFromPath:filename] forKey:@"type"];
- NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate];
- NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000];
- [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
-
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- } else {
- // We couldn't find the asset. Send the appropriate error.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- }
- };
- ALAssetsLibraryAccessFailu
<TRUNCATED>
[5/6] CB-5406: Split iOS file plugin into modules
Posted by ia...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7bb39777/src/ios/CDVLocalFilesystem.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVLocalFilesystem.m b/src/ios/CDVLocalFilesystem.m
new file mode 100644
index 0000000..0864017
--- /dev/null
+++ b/src/ios/CDVLocalFilesystem.m
@@ -0,0 +1,655 @@
+/*
+ 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 <Cordova/CDV.h>
+#import <MobileCoreServices/MobileCoreServices.h>
+#import <sys/xattr.h>
+
+@implementation CDVLocalFilesystem
+@synthesize fsRoot=_fsRoot;
+
+- (id) initWithName:(NSString *)name root:(NSString *)fsRoot
+{
+ if (self) {
+ _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;
+ 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) {
+ NSDictionary* fileSystem = [self makeEntryForPath:url.fullPath fileSystem:url.fileSystemType isDirectory:isDir];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
+ } else {
+ // return NOT_FOUND_ERR
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+ }
+ return result;
+}
+- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystem:(int)fsType isDirectory:(BOOL)isDir
+{
+ NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5];
+ NSString* lastPart = [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: [NSNumber numberWithInt:fsType] forKey: @"filesystem"];
+
+ return dirEntry;
+}
+
+/*
+ * 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
+{
+ NSString *path = nil;
+ NSString *fullPath = url.fullPath;
+ path = [NSString stringWithFormat:@"%@%@", self.fsRoot, fullPath];
+ if ([path hasSuffix:@"/"]) {
+ path = [path substringToIndex:([path length]-1)];
+ }
+ return path;
+}
+
+
+- (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 ([options valueForKeyIsNumber:@"create"]) {
+ create = [(NSNumber*)[options valueForKey:@"create"] boolValue];
+ }
+ if ([options valueForKeyIsNumber:@"exclusive"]) {
+ exclusive = [(NSNumber*)[options valueForKey:@"exclusive"] boolValue];
+ }
+
+ if ([options valueForKeyIsNumber:@"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 {
+ CDVFilesystemURL* requestedURL = [CDVFilesystemURL fileSystemURLWithURL:[NSURL URLWithString:[requestedPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] relativeToURL:baseURI.url]]; /* TODO: UGLY - FIX */
+
+ // NSLog(@"reqFullPath = %@", reqFullPath);
+ 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 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 fileSystem:baseURI.fileSystemType 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 fileSystem:newURI.fileSystemType isDirectory:bIsDir]];
+ } else {
+ // invalid path or file does not exist
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+ }
+ return result;
+}
+
+- (void)getMetadataForURL:(CDVFilesystemURL *)url callback:(void (^)(CDVPluginResult *))callback
+{
+
+ NSFileManager* fileMgr = [[NSFileManager alloc] init];
+ NSError* __autoreleasing error = nil;
+
+ CDVPluginResult *result;
+ NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:[self fileSystemPathForURL:url] error:&error];
+
+ if (fileAttribs) {
+ NSDate* modDate = [fileAttribs fileModificationDate];
+ if (modDate) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[modDate timeIntervalSince1970] * 1000];
+ }
+ } else {
+ // didn't get fileAttribs
+ CDVFileError errorCode = ABORT_ERR;
+ NSLog(@"error getting metadata: %@", [error localizedDescription]);
+ if ([error code] == NSFileNoSuchFileError) {
+ errorCode = NOT_FOUND_ERR;
+ }
+ // log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode];
+ }
+ if (!result) {
+ // invalid path or file does not exist
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION];
+ }
+ callback(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]]) {
+ 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] fileSystem:localURI.fileSystemType 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: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];
+ [fileStream open];
+
+ bytesWritten = [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<CDVFileSystem> *)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 = [self 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 fileSystem:srcURL.fileSystemType isDirectory:bSrcIsDir]; // should be the same type as source
+ 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 fileSystem:destURL.fileSystemType 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";
+ }
+ }
+ 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];
+ NSFileManager* fileMgr = [[NSFileManager alloc] init];
+ BOOL bIsDir = NO;
+ // make sure it exists and is not a directory
+ BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory:&bIsDir];
+ if (!bExists || bIsDir) {
+ callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]);
+ } else {
+ // create dictionary of file info
+ NSError* __autoreleasing error = nil;
+ NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:path error:&error];
+ NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
+ [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"];
+ [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"];
+ NSDate* modDate = [fileAttrs fileModificationDate];
+ NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000];
+ [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
+ callback([CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]);
+ }
+}
+
+@end
[4/6] git commit: CB-5406: Factor out filesystem providers in iOS
Posted by ia...@apache.org.
CB-5406: Factor out filesystem providers in iOS
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/64187ca1
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/64187ca1
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/64187ca1
Branch: refs/heads/dev
Commit: 64187ca1be3e5b0a8d366959d1946a99ba44c198
Parents: b8c4f85
Author: Ian Clelland <ic...@chromium.org>
Authored: Mon Nov 18 14:49:56 2013 -0500
Committer: Ian Clelland <ic...@chromium.org>
Committed: Mon Nov 18 14:54:01 2013 -0500
----------------------------------------------------------------------
src/ios/CDVFile.h | 19 +-
src/ios/CDVFile.m | 2059 +++++++++++++++++++++++++-----------------------
2 files changed, 1099 insertions(+), 979 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/64187ca1/src/ios/CDVFile.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVFile.h b/src/ios/CDVFile.h
index c5877f1..ef17a62 100644
--- a/src/ios/CDVFile.h
+++ b/src/ios/CDVFile.h
@@ -39,7 +39,8 @@ typedef int CDVFileError;
enum CDVFileSystemType {
TEMPORARY = 0,
- PERSISTENT = 1
+ PERSISTENT = 1,
+ ASSETS_LIBRARY = 2,
};
typedef int CDVFileSystemType;
@@ -52,13 +53,12 @@ extern NSString* const kCDVAssetsLibraryPrefix;
NSString* persistentPath;
NSString* temporaryPath;
+ NSMutableArray* fileSystems_;
BOOL userHasAllowed;
}
+
- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath;
-- (NSString*)getAppPath:(NSString*)pathFragment;
-- (NSDictionary*)getDirectoryEntry:(NSString*)fullPath isDirectory:(BOOL)isDir; //DEPRECATE HARD
- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystem:(int)fsType isDirectory:(BOOL)isDir;
-- (NSString *)fileSystemPathForLocalURI:(NSURL *)uri;
/* Exec API */
- (void)requestFileSystem:(CDVInvokedUrlCommand*)command;
@@ -81,22 +81,15 @@ extern NSString* const kCDVAssetsLibraryPrefix;
- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command;
- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command;
- (void)truncate:(CDVInvokedUrlCommand*)command;
-
-- (CDVPluginResult*)doRemove:(NSString*)fullPath;
-- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest;
- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy;
-- (void)readFileWithPath:(NSString*)path start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString*, CDVFileError))callback;
-- (NSString*)getMimeTypeFromPath:(NSString*)fullPath;
-
-- (void)writeToFile:(NSString*)fileName withData:(NSData*)data append:(BOOL)shouldAppend callback:(NSString*)callbackId;
-- (void)writeToFile:(NSString*)fileName withString:(NSString*)data encoding:(NSStringEncoding)encoding append:(BOOL)shouldAppend callback:(NSString*)callbackId;
-- (unsigned long long)truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos;
@property (nonatomic, strong) NSString* appDocsPath;
@property (nonatomic, strong) NSString* appLibraryPath;
@property (nonatomic, strong) NSString* appTempPath;
@property (nonatomic, strong) NSString* persistentPath;
@property (nonatomic, strong) NSString* temporaryPath;
+@property (nonatomic, strong) NSMutableArray* fileSystems;
+
@property BOOL userHasAllowed;
@end
[2/6] git commit: CB-5406: Update iOS native code to use filesystem
URLs internally
Posted by ia...@apache.org.
CB-5406: Update iOS native code to use filesystem URLs internally
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/b3b6a83f
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/b3b6a83f
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/b3b6a83f
Branch: refs/heads/dev
Commit: b3b6a83f0c18d0416245b4bc7375ac07fa819129
Parents: 1dfdf0f
Author: Ian Clelland <ic...@chromium.org>
Authored: Mon Nov 18 13:26:54 2013 -0500
Committer: Ian Clelland <ic...@chromium.org>
Committed: Mon Nov 18 14:53:40 2013 -0500
----------------------------------------------------------------------
plugin.xml | 5 +-
src/ios/CDVFile.h | 24 +-
src/ios/CDVFile.m | 688 ++++++++++++++++++++++++---------------------
www/ios/FileSystem.js | 27 ++
4 files changed, 417 insertions(+), 327 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/b3b6a83f/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index 0cc310d..d4091f8 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -115,9 +115,12 @@ xmlns:android="http://schemas.android.com/apk/res/android"
<source-file src="src/ios/CDVFile.m" />
<!-- ios specific file apis -->
- <js-module src="www/ios/Entry.js" name="Entry1">
+ <js-module src="www/ios/Entry.js" name="iosEntry">
<merges target="window.Entry" />
</js-module>
+ <js-module src="www/ios/FileSystem.js" name="iosFileSystem">
+ <merges target="window.FileSystem" />
+ </js-module>
<framework src="AssetsLibrary.framework" />
<framework src="MobileCoreServices.framework" />
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/b3b6a83f/src/ios/CDVFile.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVFile.h b/src/ios/CDVFile.h
index 54d25f0..c5877f1 100644
--- a/src/ios/CDVFile.h
+++ b/src/ios/CDVFile.h
@@ -56,9 +56,12 @@ extern NSString* const kCDVAssetsLibraryPrefix;
}
- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath;
- (NSString*)getAppPath:(NSString*)pathFragment;
-// -(NSString*) getFullPath: (NSString*)pathFragment;
+- (NSDictionary*)getDirectoryEntry:(NSString*)fullPath isDirectory:(BOOL)isDir; //DEPRECATE HARD
+- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystem:(int)fsType isDirectory:(BOOL)isDir;
+- (NSString *)fileSystemPathForLocalURI:(NSURL *)uri;
+
+/* Exec API */
- (void)requestFileSystem:(CDVInvokedUrlCommand*)command;
-- (NSDictionary*)getDirectoryEntry:(NSString*)fullPath isDirectory:(BOOL)isDir;
- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command;
- (void)getDirectory:(CDVInvokedUrlCommand*)command;
- (void)getFile:(CDVInvokedUrlCommand*)command;
@@ -66,30 +69,25 @@ extern NSString* const kCDVAssetsLibraryPrefix;
- (void)getMetadata:(CDVInvokedUrlCommand*)command;
- (void)removeRecursively:(CDVInvokedUrlCommand*)command;
- (void)remove:(CDVInvokedUrlCommand*)command;
-- (CDVPluginResult*)doRemove:(NSString*)fullPath;
- (void)copyTo:(CDVInvokedUrlCommand*)command;
- (void)moveTo:(CDVInvokedUrlCommand*)command;
-- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest;
-- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy;
-// - (void) toURI:(CDVInvokedUrlCommand*)command;
- (void)getFileMetadata:(CDVInvokedUrlCommand*)command;
- (void)readEntries:(CDVInvokedUrlCommand*)command;
-
- (void)readAsText:(CDVInvokedUrlCommand*)command;
- (void)readAsDataURL:(CDVInvokedUrlCommand*)command;
- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command;
-- (NSString*)getMimeTypeFromPath:(NSString*)fullPath;
- (void)write:(CDVInvokedUrlCommand*)command;
- (void)testFileExists:(CDVInvokedUrlCommand*)command;
- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command;
-// - (void) createDirectory:(CDVInvokedUrlCommand*)command;
-// - (void) deleteDirectory:(CDVInvokedUrlCommand*)command;
-// - (void) deleteFile:(CDVInvokedUrlCommand*)command;
- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command;
- (void)truncate:(CDVInvokedUrlCommand*)command;
-// - (BOOL) fileExists:(NSString*)fileName;
-// - (BOOL) directoryExists:(NSString*)dirName;
+- (CDVPluginResult*)doRemove:(NSString*)fullPath;
+- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest;
+- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy;
+- (void)readFileWithPath:(NSString*)path start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString*, CDVFileError))callback;
+- (NSString*)getMimeTypeFromPath:(NSString*)fullPath;
+
- (void)writeToFile:(NSString*)fileName withData:(NSData*)data append:(BOOL)shouldAppend callback:(NSString*)callbackId;
- (void)writeToFile:(NSString*)fileName withString:(NSString*)data encoding:(NSStringEncoding)encoding append:(BOOL)shouldAppend callback:(NSString*)callbackId;
- (unsigned long long)truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos;
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/b3b6a83f/src/ios/CDVFile.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVFile.m b/src/ios/CDVFile.m
index 6b2602d..2f41046 100644
--- a/src/ios/CDVFile.m
+++ b/src/ios/CDVFile.m
@@ -25,6 +25,43 @@
#import <MobileCoreServices/MobileCoreServices.h>
#import <sys/xattr.h>
+@interface CDVFilesystemURL : NSObject {
+ NSURL *url_;
+ CDVFileSystemType fileSystemType_;
+ NSString *fullPath_;
+ NSString *fileSystemPath_;
+}
+
+- (id) initWithString:(NSString*)strURL;
+- (id) initWithURL:(NSURL*)URL;
+
+@property (atomic) NSURL *url;
+@property (atomic) CDVFileSystemType fileSystemType;
+@property (atomic) NSString *fullPath;
+@property (atomic) NSString *fileSystemPath;
+
+@end
+
+@implementation CDVFilesystemURL
+@synthesize url=url_;
+@synthesize fileSystemType=fileSystemType_;
+@synthesize fullPath=fullPath_, fileSystemPath=fileSystemPath_;
+
+- (id) initWithString:(NSString *)strURL
+{
+ NSURL *decodedURL = [NSURL URLWithString:strURL];
+ return [self initWithURL:decodedURL];
+}
+
+-(id) initWithURL:(NSURL *)URL
+{
+ url_ = URL;
+ fileSystemType_ = -42;
+ return self;
+}
+
+@end
+
extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import));
#ifndef __IPHONE_5_1
@@ -32,6 +69,7 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import)
#endif
NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
+NSString* const kCDVAssetsLibraryScheme = @"assets-library";
@implementation CDVFile
@@ -58,6 +96,116 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
return self;
}
+- (void)updateFileSystemURL:(CDVFilesystemURL *)fsURL;
+{
+ fsURL.fileSystemType = [self filesystemTypeForLocalURI:fsURL.url];
+ fsURL.fileSystemPath = [self fileSystemPathForLocalURI:fsURL.url];
+ fsURL.fullPath = [self fullPathForFileSystemPath:fsURL.fileSystemPath];
+}
+
+- (CDVFilesystemURL *)fileSystemURLWithString:(NSString *)strURL
+{
+ CDVFilesystemURL* fsURL = [[CDVFilesystemURL alloc] initWithString:strURL];
+ if (fsURL) {
+ [self updateFileSystemURL:fsURL];
+ }
+ return fsURL;
+}
+
+- (CDVFilesystemURL *)fileSystemURLWithURL:(NSURL *)URL
+{
+ CDVFilesystemURL* fsURL = [[CDVFilesystemURL alloc] initWithURL:URL];
+ if (fsURL) {
+ [self updateFileSystemURL:fsURL];
+ }
+ return fsURL;
+}
+
+/*
+ * 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 *)fileSystemPathForLocalURI:(NSURL *)uri
+{
+ NSString *path = nil;
+ int fsType = [self filesystemTypeForLocalURI:uri];
+ NSString *fullPath = [self fullPathForLocalURI:uri];
+ if (fsType == TEMPORARY) {
+ path = [NSString stringWithFormat:@"%@%@", self.appTempPath, fullPath];
+ } else if (fsType == PERSISTENT) {
+ path = [NSString stringWithFormat:@"%@%@", self.appDocsPath, fullPath];
+ } else {
+ return nil;
+ }
+ if ([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 *)fullPathForFileSystemPath:(NSString *)fsPath
+{
+ if ([fsPath hasPrefix:self.appTempPath]) {
+ return [fsPath substringFromIndex:[self.appTempPath length]];
+ } else if ([fsPath hasPrefix:self.appDocsPath]) {
+ return [fsPath substringFromIndex:[self.appDocsPath length]];
+ }
+ 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
+{
+ int fsType = [self filesystemTypeForLocalURI:uri];
+ if (fsType == TEMPORARY) {
+ return [[uri path] substringFromIndex:10];
+ } else if (fsType == PERSISTENT) {
+ return [[uri path] substringFromIndex:11];
+ }
+ return nil;
+}
+
+/*
+ * IN
+ * NSString localURI
+ * OUT
+ * int FileSystem type for this URI, or -1 if it is not recognized.
+ */
+- (CDVFileSystemType)filesystemTypeForLocalURI:(NSURL *)uri
+{
+ if ([[uri scheme] isEqualToString:@"filesystem"] && [[uri host] isEqualToString:@"localhost"]) {
+ if ([[uri path] hasPrefix:@"/temporary"]) {
+ return TEMPORARY;
+ } else if ([[uri path] hasPrefix:@"/persistent"]) {
+ return PERSISTENT;
+ }
+ }
+ return -1;
+}
+
+
- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath
{
NSFileManager* fMgr = [[NSFileManager alloc] init];
@@ -70,7 +218,8 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
return pNumAvail;
}
-// figure out if the pathFragment represents a persistent of temporary directory and return the full application path.
+// figure out if the (device local file sytstem) pathFragment represents a persistent or temporary directory
+// and return the full application path.
// returns nil if path is not persistent or temporary
- (NSString*)getAppPath:(NSString*)pathFragment
{
@@ -93,31 +242,6 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
return appPath;
}
-/* get the full path to this resource
- * IN
- * NSString* pathFragment - full Path from File or Entry object (includes system path info)
- * OUT
- * NSString* fullPath - full iOS path to this resource, nil if not found
- */
-
-/* Was here in order to NOT have to return full path, but W3C synchronous DirectoryEntry.toURI() killed that idea since I can't call into iOS to
- * resolve full URI. Leaving this code here in case W3C spec changes.
--(NSString*) getFullPath: (NSString*)pathFragment
-{
- return pathFragment;
- NSString* fullPath = nil;
- NSString *appPath = [ self getAppPath: pathFragment];
- if (appPath){
-
- // remove last component from appPath
- NSRange range = [appPath rangeOfString:@"/" options: NSBackwardsSearch];
- NSString* newPath = [appPath substringToIndex:range.location];
- // add pathFragment to get test Path
- fullPath = [newPath stringByAppendingPathComponent:pathFragment];
- }
- return fullPath;
-} */
-
/* Request the File System info
*
* IN:
@@ -151,8 +275,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:NOT_FOUND_ERR];
NSLog(@"iOS only supports TEMPORARY and PERSISTENT file systems");
} else {
- // NSString* fullPath = [NSString stringWithFormat:@"/%@", (type == 0 ? [self.appTempPath lastPathComponent] : [self.appDocsPath lastPathComponent])];
- NSString* fullPath = (type == 0 ? self.appTempPath : self.appDocsPath);
+ NSString* fullPath = @"/";
// check for avail space for size request
NSNumber* pNumAvail = [self checkFreeDiskSpace:fullPath];
// NSLog(@"Free space: %@", [NSString stringWithFormat:@"%qu", [ pNumAvail unsignedLongLongValue ]]);
@@ -161,7 +284,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
} else {
NSMutableDictionary* fileSystem = [NSMutableDictionary dictionaryWithCapacity:2];
[fileSystem setObject:(type == TEMPORARY ? kW3FileTemporary : kW3FilePersistent) forKey:@"name"];
- NSDictionary* dirEntry = [self getDirectoryEntry:fullPath isDirectory:YES];
+ NSDictionary* dirEntry = [self makeEntryForPath:fullPath fileSystem:type isDirectory:YES];
[fileSystem setObject:dirEntry forKey:@"root"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
}
@@ -169,40 +292,47 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
-/* Creates a dictionary representing an Entry Object
+/* Creates and returns a dictionary representing an Entry Object
*
* IN:
* NSString* fullPath of the entry
- * FileSystem type
+ * int fsType - FileSystem type
* BOOL isDirectory - YES if this is a directory, NO if is a file
* OUT:
- * NSDictionary*
- Entry object
+ * NSDictionary* Entry object
* bool as NSNumber isDirectory
* bool as NSNumber isFile
* NSString* name - last part of path
* NSString* fullPath
- * fileSystem = FileSystem object - !! ignored because creates circular reference FileSystem contains DirectoryEntry which contains FileSystem.....!!
+ * filesystem = FileSystem type -- actual filesystem will be created on the JS side if necessary, to avoid
+ * creating circular reference (FileSystem contains DirectoryEntry which contains FileSystem.....!!)
*/
-- (NSDictionary*)getDirectoryEntry:(NSString*)fullPath isDirectory:(BOOL)isDir
+- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystem:(int)fsType isDirectory:(BOOL)isDir
{
- NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:4];
+ NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5];
NSString* lastPart = [fullPath lastPathComponent];
-
+ if (isDir && ![fullPath hasSuffix:@"/"]) {
+ fullPath = [fullPath stringByAppendingString:@"/"];
+ }
[dirEntry setObject:[NSNumber numberWithBool:!isDir] forKey:@"isFile"];
[dirEntry setObject:[NSNumber numberWithBool:isDir] forKey:@"isDirectory"];
- // NSURL* fileUrl = [NSURL fileURLWithPath:fullPath];
- // [dirEntry setObject: [fileUrl absoluteString] forKey: @"fullPath"];
[dirEntry setObject:fullPath forKey:@"fullPath"];
[dirEntry setObject:lastPart forKey:@"name"];
+ [dirEntry setObject: [NSNumber numberWithInt:fsType] forKey: @"filesystem"];
return dirEntry;
}
+/* STRONGLY DEPRECATED */
+- (NSDictionary*)getDirectoryEntry:(NSString*)fullPath isDirectory:(BOOL)isDir
+{
+ return [self makeEntryForPath:fullPath fileSystem:42 isDirectory:isDir];
+}
+
/*
* Given a URI determine the File System information associated with it and return an appropriate W3C entry object
* IN
- * NSString* fileURI - currently requires full file URI
+ * NSString* localURI: Should be an escaped local filesystem URI
* OUT
* Entry object
* bool isDirectory
@@ -214,59 +344,49 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command
{
// arguments
- NSString* inputUri = [command.arguments objectAtIndex:0];
+ CDVFilesystemURL* inputUri = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
+ CDVPluginResult* result = [self entryForLocalURI:inputUri];
+ if (result != nil) {
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ }
+}
- // don't know if string is encoded or not so unescape
- NSString* cleanUri = [inputUri stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- // now escape in order to create URL
- NSString* strUri = [cleanUri stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- NSURL* testUri = [NSURL URLWithString:strUri];
+/*
+ * 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;
-
- if (!testUri) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR];
- } else if ([testUri isFileURL]) {
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- NSString* path = [testUri path];
- // NSLog(@"url path: %@", path);
- BOOL isDir = NO;
- // see if exists and is file or dir
- BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory:&isDir];
- if (bExists) {
- // see if it contains docs path or temp path
- NSString* foundFullPath = nil;
- if ([path hasPrefix:self.appDocsPath]) {
- foundFullPath = self.appDocsPath;
- } else if ([path hasPrefix:self.appTempPath]) {
- foundFullPath = self.appTempPath;
- }
-
- if (foundFullPath == nil) {
- // error SECURITY_ERR - not one of the two paths types supported
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:SECURITY_ERR];
- } else {
- NSDictionary* fileSystem = [self getDirectoryEntry:path isDirectory:isDir];
+ if ([[url.url scheme] isEqualToString:@"assets-library"]) {
+ NSDictionary* fileSystem = [self getDirectoryEntry:[url.url absoluteString] isDirectory:NO];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
+ } else {
+ if (url.fileSystemType == -1) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR];
+ } else {
+ NSFileManager* fileMgr = [[NSFileManager alloc] init];
+ BOOL isDir = NO;
+ // see if exists and is file or dir
+ BOOL bExists = [fileMgr fileExistsAtPath:url.fileSystemPath isDirectory:&isDir];
+ if (bExists) {
+ NSDictionary* fileSystem = [self makeEntryForPath:url.fullPath fileSystem:url.fileSystemType isDirectory:isDir];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
+ } else {
+ // return NOT_FOUND_ERR
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
}
- } else {
- // return NOT_FOUND_ERR
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
}
- } else if ([strUri hasPrefix:@"assets-library://"]) {
- NSDictionary* fileSystem = [self getDirectoryEntry:strUri isDirectory:NO];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
- } else {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR];
- }
-
- if (result != nil) {
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
+ return result;
}
/* Part of DirectoryEntry interface, creates or returns the specified directory
* IN:
- * NSString* fullPath - full path for this directory
+ * 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 -
@@ -310,9 +430,9 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
/* Part of DirectoryEntry interface, creates or returns the specified file
* IN:
- * NSString* fullPath - full path for this file
- * NSString* path - file to be created/returned; may be full path or relative path
- * NSDictionary* - Flags object
+ * 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
@@ -320,18 +440,16 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
* 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
{
- // arguments are URL encoded
- NSString* fullPath = [command.arguments objectAtIndex:0];
+ NSString* baseURIstr = [command.arguments objectAtIndex:0];
+ CDVFilesystemURL* baseURI = [self fileSystemURLWithString:baseURIstr];
NSString* requestedPath = [command.arguments objectAtIndex:1];
NSDictionary* options = [command.arguments objectAtIndex:2 withDefault:nil];
// return unsupported result for assets-library URLs
- if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
+ if ([[baseURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFile not supported for assets-library URLs."];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
return;
@@ -358,22 +476,12 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
if ([requestedPath rangeOfString:@":"].location != NSNotFound) {
errorCode = ENCODING_ERR;
} else {
- // was full or relative path provided?
- NSRange range = [requestedPath rangeOfString:fullPath];
- BOOL bIsFullPath = range.location != NSNotFound;
-
- NSString* reqFullPath = nil;
-
- if (!bIsFullPath) {
- reqFullPath = [fullPath stringByAppendingPathComponent:requestedPath];
- } else {
- reqFullPath = requestedPath;
- }
-
+ CDVFilesystemURL* requestedURL = [self fileSystemURLWithURL:[NSURL URLWithString:[requestedPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] relativeToURL:baseURI.url]]; /* TODO: UGLY - FIX */
+
// NSLog(@"reqFullPath = %@", reqFullPath);
NSFileManager* fileMgr = [[NSFileManager alloc] init];
BOOL bIsDir;
- BOOL bExists = [fileMgr fileExistsAtPath:reqFullPath isDirectory:&bIsDir];
+ BOOL bExists = [fileMgr fileExistsAtPath:requestedURL.fileSystemPath isDirectory:&bIsDir];
if (bExists && (create == NO) && (bIsDir == !bDirRequest)) {
// path exists and is of requested type - return TYPE_MISMATCH_ERR
errorCode = TYPE_MISMATCH_ERR;
@@ -392,10 +500,10 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
if (!bExists && (create == YES)) {
if (bDirRequest) {
// create the dir
- bSuccess = [fileMgr createDirectoryAtPath:reqFullPath withIntermediateDirectories:NO attributes:nil error:&pError];
+ bSuccess = [fileMgr createDirectoryAtPath:requestedURL.fileSystemPath withIntermediateDirectories:NO attributes:nil error:&pError];
} else {
// create the empty file
- bSuccess = [fileMgr createFileAtPath:reqFullPath contents:nil attributes:nil];
+ bSuccess = [fileMgr createFileAtPath:requestedURL.fileSystemPath contents:nil attributes:nil];
}
}
if (!bSuccess) {
@@ -406,7 +514,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
} else {
// NSLog(@"newly created file/dir (%@) exists: %d", reqFullPath, [fileMgr fileExistsAtPath:reqFullPath]);
// file existed or was created
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:reqFullPath isDirectory:bDirRequest]];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:requestedURL.fullPath fileSystem:baseURI.fileSystemType isDirectory:bDirRequest]];
}
} // are all possible conditions met?
}
@@ -424,44 +532,36 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
* If this Entry is the root of its filesystem, its parent is itself.
* IN:
* NSArray* arguments
- * 0 - NSString* fullPath
+ * 0 - NSString* localURI
* NSMutableDictionary* options
* empty
*/
- (void)getParent:(CDVInvokedUrlCommand*)command
{
// arguments are URL encoded
- NSString* fullPath = [command.arguments objectAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
// we don't (yet?) support getting the parent of an asset
- if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
+ if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
return;
}
CDVPluginResult* result = nil;
- NSString* newPath = nil;
-
- if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) {
+ CDVFilesystemURL *newURI = nil;
+ if ([localURI.fullPath isEqualToString:@""]) {
// return self
- newPath = fullPath;
+ newURI = localURI;
} else {
- // since this call is made from an existing Entry object - the parent should already exist so no additional error checking
- // remove last component and return Entry
- NSRange range = [fullPath rangeOfString:@"/" options:NSBackwardsSearch];
- newPath = [fullPath substringToIndex:range.location];
- }
-
- if (newPath) {
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- BOOL bIsDir;
- BOOL bExists = [fileMgr fileExistsAtPath:newPath isDirectory:&bIsDir];
- if (bExists) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:newPath isDirectory:bIsDir]];
- }
+ newURI = [self fileSystemURLWithURL:[localURI.url URLByDeletingLastPathComponent]]; /* TODO: UGLY - FIX */
}
- if (!result) {
+ NSFileManager* fileMgr = [[NSFileManager alloc] init];
+ BOOL bIsDir;
+ BOOL bExists = [fileMgr fileExistsAtPath:newURI.fileSystemPath isDirectory:&bIsDir];
+ if (bExists) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:newURI.fullPath fileSystem:newURI.fileSystemType isDirectory:bIsDir]];
+ } else {
// invalid path or file does not exist
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
}
@@ -475,10 +575,12 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)getMetadata:(CDVInvokedUrlCommand*)command
{
// arguments
- NSString* argPath = [command.arguments objectAtIndex:0];
+ NSString* localURIstr = [command.arguments objectAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:localURIstr];
+
__block CDVPluginResult* result = nil;
- if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
+ if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
// In this case, we need to use an asynchronous method to retrieve the file.
// Because of this, we can't just assign to `result` and send it at the end of the method.
// Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
@@ -502,16 +604,14 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
};
ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
- [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock];
+ [assetsLibrary assetForURL:[NSURL URLWithString:localURIstr] resultBlock:resultBlock failureBlock:failureBlock];
return;
}
- NSString* testPath = argPath; // [self getFullPath: argPath];
-
NSFileManager* fileMgr = [[NSFileManager alloc] init];
NSError* __autoreleasing error = nil;
- NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:testPath error:&error];
+ NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:localURI.fileSystemPath error:&error];
if (fileAttribs) {
NSDate* modDate = [fileAttribs fileModificationDate];
@@ -542,13 +642,15 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)setMetadata:(CDVInvokedUrlCommand*)command
{
// arguments
- NSString* filePath = [command.arguments objectAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
NSDictionary* options = [command.arguments objectAtIndex:1 withDefault:nil];
+
CDVPluginResult* result = nil;
BOOL ok = NO;
// setMetadata doesn't make sense for asset library files
- if (![filePath hasPrefix:kCDVAssetsLibraryPrefix]) {
+ if (![[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
+ NSString* filePath = localURI.fileSystemPath;
// 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";
@@ -582,7 +684,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
/* removes the directory or file entry
* IN:
* NSArray* arguments
- * 0 - NSString* fullPath
+ * 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
@@ -591,24 +693,24 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)remove:(CDVInvokedUrlCommand*)command
{
// arguments
- NSString* fullPath = [command.arguments objectAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
CDVPluginResult* result = nil;
CDVFileError errorCode = 0; // !! 0 not currently defined
// return error for assets-library URLs
- if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
+ if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
errorCode = INVALID_MODIFICATION_ERR;
- } else if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) {
+ } else if ([localURI.fullPath isEqualToString:@""]) {
// error if try to remove top level (documents or tmp) dir
errorCode = NO_MODIFICATION_ALLOWED_ERR;
} else {
NSFileManager* fileMgr = [[NSFileManager alloc] init];
BOOL bIsDir = NO;
- BOOL bExists = [fileMgr fileExistsAtPath:fullPath isDirectory:&bIsDir];
+ BOOL bExists = [fileMgr fileExistsAtPath:localURI.fileSystemPath isDirectory:&bIsDir];
if (!bExists) {
errorCode = NOT_FOUND_ERR;
}
- if (bIsDir && ([[fileMgr contentsOfDirectoryAtPath:fullPath error:nil] count] != 0)) {
+ if (bIsDir && ([[fileMgr contentsOfDirectoryAtPath:localURI.fileSystemPath error:nil] count] != 0)) {
// dir is not empty
errorCode = INVALID_MODIFICATION_ERR;
}
@@ -617,7 +719,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
} else {
// perform actual remove
- result = [self doRemove:fullPath];
+ result = [self doRemove:localURI.fileSystemPath];
}
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
@@ -625,7 +727,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
/* recursively removes the directory
* IN:
* NSArray* arguments
- * 0 - NSString* fullPath
+ * 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
@@ -633,22 +735,21 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)removeRecursively:(CDVInvokedUrlCommand*)command
{
// arguments
- NSString* fullPath = [command.arguments objectAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
// return unsupported result for assets-library URLs
- if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
+ if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"removeRecursively not supported for assets-library URLs."];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
return;
}
CDVPluginResult* result = nil;
-
// error if try to remove top level (documents or tmp) dir
- if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) {
+ if ([localURI.fullPath isEqualToString:@""]) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
} else {
- result = [self doRemove:fullPath];
+ result = [self doRemove:localURI.fileSystemPath];
}
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
@@ -674,7 +775,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
} else {
// see if we can give a useful error
CDVFileError errorCode = ABORT_ERR;
- NSLog(@"error getting metadata: %@", [pError localizedDescription]);
+ NSLog(@"error removing filesystem entry at %@: %@", fullPath, [pError localizedDescription]);
if ([pError code] == NSFileNoSuchFileError) {
errorCode = NOT_FOUND_ERR;
} else if ([pError code] == NSFileWriteNoPermissionError) {
@@ -732,44 +833,45 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
/* Copy/move a file or directory to a new location
* IN:
* NSArray* arguments
- * 0 - NSString* fullPath of entry
- * 1 - NSString* newName the new name of the entry, defaults to the current name
- * NSMutableDictionary* options - DirectoryEntry to which to copy the entry
+ * 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* srcFullPath = [arguments objectAtIndex:0];
- NSString* destRootPath = [arguments objectAtIndex:1];
- // optional argument
- NSString* newName = ([arguments count] > 2) ? [arguments objectAtIndex:2] : [srcFullPath lastPathComponent]; // use last component from appPath if new name not provided
+ NSString* srcURLstr = [arguments objectAtIndex:0];
+ NSString* destURLstr = [arguments objectAtIndex:1];
__block CDVPluginResult* result = nil;
CDVFileError errCode = 0; // !! Currently 0 is not defined, use this to signal error !!
- /*NSString* destRootPath = nil;
- NSString* key = @"fullPath";
- if([options valueForKeyIsString:key]){
- destRootPath = [options objectForKey:@"fullPath"];
- }*/
-
- if (!destRootPath) {
- // no destination provided
+ if (!srcURLstr || !destURLstr) {
+ // either no source or no destination provided
errCode = NOT_FOUND_ERR;
- } else if ([newName rangeOfString:@":"].location != NSNotFound) {
+ } else {
+ CDVFilesystemURL* srcURL = [self fileSystemURLWithString:srcURLstr];
+ CDVFilesystemURL* destURL = [self fileSystemURLWithString:destURLstr];
+ NSString* srcFullPath = srcURL.fileSystemPath;
+ NSString* destRootPath = destURL.fileSystemPath;
+
+ // optional argument; use last component from srcFullPath if new name not provided
+ NSString* newName = ([arguments count] > 2) ? [arguments objectAtIndex:2] : [srcFullPath lastPathComponent];
+ if ([newName rangeOfString:@":"].location != NSNotFound) {
// invalid chars in new name
errCode = ENCODING_ERR;
} else {
- NSString* newFullPath = [destRootPath stringByAppendingPathComponent:newName];
+ NSString* newFileSystemPath = [destRootPath stringByAppendingPathComponent:newName];
+ NSString* newFullPath = [self fullPathForFileSystemPath:newFileSystemPath];
+
NSFileManager* fileMgr = [[NSFileManager alloc] init];
- if ([newFullPath isEqualToString:srcFullPath]) {
+ if ([newFileSystemPath isEqualToString:srcFullPath]) {
// source and destination can not be the same
errCode = INVALID_MODIFICATION_ERR;
- } else if ([srcFullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
+ } else if ([[srcURL.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
if (bCopy) {
// Copying (as opposed to moving) an assets library file is okay.
// In this case, we need to use an asynchronous method to retrieve the file.
@@ -783,7 +885,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
return;
- } else if ([fileMgr fileExistsAtPath:newFullPath]) {
+ } else if ([fileMgr fileExistsAtPath:newFileSystemPath]) {
// A file already exists at the destination path.
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:PATH_EXISTS_ERR];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
@@ -795,8 +897,8 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
Byte* buffer = (Byte*)malloc([assetRepresentation size]);
NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
- [data writeToFile:newFullPath atomically:YES];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:newFullPath isDirectory:NO]];
+ [data writeToFile:newFileSystemPath atomically:YES];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:newFileSystemPath isDirectory:NO]];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
} else {
// We couldn't find the asset. Send the appropriate error.
@@ -823,7 +925,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
BOOL bNewIsDir = NO;
BOOL bSrcExists = [fileMgr fileExistsAtPath:srcFullPath isDirectory:&bSrcIsDir];
BOOL bDestExists = [fileMgr fileExistsAtPath:destRootPath isDirectory:&bDestIsDir];
- BOOL bNewExists = [fileMgr fileExistsAtPath:newFullPath isDirectory:&bNewIsDir];
+ BOOL bNewExists = [fileMgr fileExistsAtPath:newFileSystemPath isDirectory:&bNewIsDir];
if (!bSrcExists || !bDestExists) {
// the source or the destination root does not exist
errCode = NOT_FOUND_ERR;
@@ -834,14 +936,14 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
NSError* __autoreleasing error = nil;
BOOL bSuccess = NO;
if (bCopy) {
- if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFullPath] /*[newFullPath hasPrefix:srcFullPath]*/) {
+ 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:newFullPath error:&error];
+ bSuccess = [fileMgr copyItemAtPath:srcFullPath toPath:newFileSystemPath error:&error];
}
} else { // move
// iOS requires that destination must not exist before calling moveTo
@@ -850,35 +952,35 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
if (!bSrcIsDir && (bNewExists && bNewIsDir)) {
// can't move a file to directory
errCode = INVALID_MODIFICATION_ERR;
- } else if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFullPath]) { // [newFullPath hasPrefix:srcFullPath]){
+ } 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:newFullPath error:NULL] count] != 0)) {
+ if (bNewIsDir && ([[fileMgr contentsOfDirectoryAtPath:newFileSystemPath error:NULL] count] != 0)) {
// can't move dir to a dir that is not empty
errCode = INVALID_MODIFICATION_ERR;
- newFullPath = nil; // so we won't try to move
+ newFileSystemPath = nil; // so we won't try to move
} else {
// remove destination so can perform the moveItemAtPath
- bSuccess = [fileMgr removeItemAtPath:newFullPath error:NULL];
+ bSuccess = [fileMgr removeItemAtPath:newFileSystemPath error:NULL];
if (!bSuccess) {
errCode = INVALID_MODIFICATION_ERR; // is this the correct error?
- newFullPath = nil;
+ newFileSystemPath = nil;
}
}
- } else if (bNewIsDir && [newFullPath hasPrefix:srcFullPath]) {
+ } else if (bNewIsDir && [newFileSystemPath hasPrefix:srcFullPath]) {
// can't move a directory inside itself or to any child at any depth;
errCode = INVALID_MODIFICATION_ERR;
- newFullPath = nil;
+ newFileSystemPath = nil;
}
- if (newFullPath != nil) {
- bSuccess = [fileMgr moveItemAtPath:srcFullPath toPath:newFullPath error:&error];
+ 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 getDirectoryEntry:newFullPath isDirectory:bSrcIsDir]; // should be the same type as source
+ NSDictionary* newEntry = [self makeEntryForPath:newFullPath fileSystem:srcURL.fileSystemType isDirectory:bSrcIsDir]; // should be the same type as source
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry];
} else {
errCode = INVALID_MODIFICATION_ERR; // catch all
@@ -895,112 +997,76 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
}
}
}
+ }
if (errCode > 0) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errCode];
}
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
-/* return the URI to the entry
- * IN:
- * NSArray* arguments
- * 0 - NSString* fullPath of entry
- * 1 - desired mime type of entry - ignored - always returns file://
- */
-
-/* Not needed since W3C toURI is synchronous. Leaving code here for now in case W3C spec changes.....
-- (void) toURI:(CDVInvokedUrlCommand*)command
-{
- NSString* callbackId = command.callbackId;
- NSString* argPath = [command.arguments objectAtIndex:0];
- PluginResult* result = nil;
- NSString* jsString = nil;
-
- NSString* fullPath = [self getFullPath: argPath];
- if (fullPath) {
- // do we need to make sure the file actually exists?
- // create file uri
- NSString* strUri = [fullPath stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
- NSURL* fileUrl = [NSURL fileURLWithPath:strUri];
- if (fileUrl) {
- result = [PluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: [fileUrl absoluteString]];
- jsString = [result toSuccessCallbackString:callbackId];
- } // else NOT_FOUND_ERR
- }
- if(!jsString) {
- // was error
- result = [PluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: NOT_FOUND_ERR cast: @"window.localFileSystem._castError"];
- jsString = [result toErrorCallbackString:callbackId];
- }
-
- [self writeJavascript:jsString];
-}*/
- (void)getFileMetadata:(CDVInvokedUrlCommand*)command
{
// arguments
- NSString* argPath = [command.arguments objectAtIndex:0];
-
+ NSString* localURIstr = [command.arguments objectAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:localURIstr];
+
__block CDVPluginResult* result = nil;
- NSString* fullPath = argPath; // [self getFullPath: argPath];
-
- if (fullPath) {
- if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
- // In this case, we need to use an asynchronous method to retrieve the file.
- // Because of this, we can't just assign to `result` and send it at the end of the method.
- // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
- ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
- if (asset) {
- // We have the asset! Populate the dictionary and send it off.
- NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
- ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
- [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"];
- [fileInfo setObject:argPath forKey:@"fullPath"];
- NSString* filename = [assetRepresentation filename];
- [fileInfo setObject:filename forKey:@"name"];
- [fileInfo setObject:[self getMimeTypeFromPath:filename] forKey:@"type"];
- NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate];
- NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000];
- [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
-
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- } else {
- // We couldn't find the asset. Send the appropriate error.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- }
- };
- ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
- // Retrieving the asset failed for some reason. Send the appropriate error.
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
- [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
- };
-
- ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
- [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock];
- return;
- } else {
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- BOOL bIsDir = NO;
- // make sure it exists and is not a directory
- BOOL bExists = [fileMgr fileExistsAtPath:fullPath isDirectory:&bIsDir];
- if (!bExists || bIsDir) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
- } else {
- // create dictionary of file info
- NSError* __autoreleasing error = nil;
- NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:&error];
+ if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
+ // In this case, we need to use an asynchronous method to retrieve the file.
+ // Because of this, we can't just assign to `result` and send it at the end of the method.
+ // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
+ ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
+ if (asset) {
+ // We have the asset! Populate the dictionary and send it off.
NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
- [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"];
- [fileInfo setObject:argPath forKey:@"fullPath"];
- [fileInfo setObject:@"" forKey:@"type"]; // can't easily get the mimetype unless create URL, send request and read response so skipping
- [fileInfo setObject:[argPath lastPathComponent] forKey:@"name"];
- NSDate* modDate = [fileAttrs fileModificationDate];
- NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000];
+ ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
+ [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"];
+ [fileInfo setObject:localURIstr forKey:@"fullPath"];
+ NSString* filename = [assetRepresentation filename];
+ [fileInfo setObject:filename forKey:@"name"];
+ [fileInfo setObject:[self getMimeTypeFromPath:filename] forKey:@"type"];
+ NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate];
+ NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000];
[fileInfo setObject:msDate forKey:@"lastModifiedDate"];
+
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo];
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } else {
+ // We couldn't find the asset. Send the appropriate error.
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
+ };
+ ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
+ // Retrieving the asset failed for some reason. Send the appropriate error.
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ };
+
+ ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+ [assetsLibrary assetForURL:[NSURL URLWithString:localURIstr] resultBlock:resultBlock failureBlock:failureBlock];
+ return;
+ } else {
+ NSFileManager* fileMgr = [[NSFileManager alloc] init];
+ BOOL bIsDir = NO;
+ // make sure it exists and is not a directory
+ BOOL bExists = [fileMgr fileExistsAtPath:localURI.fileSystemPath isDirectory:&bIsDir];
+ if (!bExists || bIsDir) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+ } else {
+ // create dictionary of file info
+ NSError* __autoreleasing error = nil;
+ NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:localURI.fileSystemPath error:&error];
+ NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
+ [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"];
+ [fileInfo setObject:localURIstr forKey:@"fullPath"];
+ [fileInfo setObject:@"" forKey:@"type"]; // can't easily get the mimetype unless create URL, send request and read response so skipping
+ [fileInfo setObject:[localURIstr lastPathComponent] forKey:@"name"];
+ NSDate* modDate = [fileAttrs fileModificationDate];
+ NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000];
+ [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo];
}
}
if (!result) {
@@ -1011,21 +1077,19 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)readEntries:(CDVInvokedUrlCommand*)command
{
- // arguments
- NSString* fullPath = [command.arguments objectAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command.arguments objectAtIndex:0]];
+ CDVPluginResult *result;
+ if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
// return unsupported result for assets-library URLs
- if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
- CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readEntries not supported for assets-library URLs."];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readEntries not supported for assets-library URLs."];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
return;
}
- CDVPluginResult* result = nil;
-
NSFileManager* fileMgr = [[NSFileManager alloc] init];
NSError* __autoreleasing error = nil;
- NSArray* contents = [fileMgr contentsOfDirectoryAtPath:fullPath error:&error];
+ NSArray* contents = [fileMgr contentsOfDirectoryAtPath:localURI.fileSystemPath error:&error];
if (contents) {
NSMutableArray* entries = [NSMutableArray arrayWithCapacity:1];
@@ -1033,10 +1097,10 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
// create an Entry (as JSON) for each file/dir
for (NSString* name in contents) {
// see if is dir or file
- NSString* entryPath = [fullPath stringByAppendingPathComponent:name];
+ NSString* entryPath = [localURI.fileSystemPath stringByAppendingPathComponent:name];
BOOL bIsDir = NO;
[fileMgr fileExistsAtPath:entryPath isDirectory:&bIsDir];
- NSDictionary* entryDict = [self getDirectoryEntry:entryPath isDirectory:bIsDir];
+ NSDictionary* entryDict = [self makeEntryForPath:[self fullPathForFileSystemPath:entryPath] fileSystem:localURI.fileSystemType isDirectory:bIsDir];
[entries addObject:entryDict];
}
}
@@ -1045,7 +1109,6 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
// assume not found but could check error for more specific error conditions
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
}
-
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
@@ -1067,7 +1130,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType);
-
+
callback(data, MIMEType, NO_ERROR);
} else {
callback(nil, nil, NOT_FOUND_ERR);
@@ -1078,7 +1141,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
NSLog(@"Error: %@", error);
callback(nil, nil, SECURITY_ERR);
};
-
+
ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
[assetsLibrary assetForURL:[NSURL URLWithString:path] resultBlock:resultBlock failureBlock:failureBlock];
} else {
@@ -1090,16 +1153,16 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
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);
}
}];
@@ -1117,7 +1180,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)readAsText:(CDVInvokedUrlCommand*)command
{
// arguments
- NSString* path = [command argumentAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command argumentAtIndex:0]];
NSString* encoding = [command argumentAtIndex:1];
NSInteger start = [[command argumentAtIndex:2] integerValue];
NSInteger end = [[command argumentAtIndex:3] integerValue];
@@ -1130,7 +1193,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
return;
}
- [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
+ [self readFileWithPath:localURI.fileSystemPath 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];
@@ -1162,11 +1225,11 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)readAsDataURL:(CDVInvokedUrlCommand*)command
{
- NSString* path = [command argumentAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command argumentAtIndex:0]];
NSInteger start = [[command argumentAtIndex:1] integerValue];
NSInteger end = [[command argumentAtIndex:2] integerValue];
- [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
+ [self readFileWithPath:localURI.fileSystemPath start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
CDVPluginResult* result = nil;
if (data != nil) {
// TODO: Would be faster to base64 encode directly to the final string.
@@ -1190,11 +1253,11 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command
{
- NSString* path = [command argumentAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command argumentAtIndex:0]];
NSInteger start = [[command argumentAtIndex:1] integerValue];
NSInteger end = [[command argumentAtIndex:2] integerValue];
- [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
+ [self readFileWithPath:localURI.fileSystemPath start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
CDVPluginResult* result = nil;
if (data != nil) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data];
@@ -1208,11 +1271,11 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)readAsBinaryString:(CDVInvokedUrlCommand*)command
{
- NSString* path = [command argumentAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command argumentAtIndex:0]];
NSInteger start = [[command argumentAtIndex:1] integerValue];
NSInteger end = [[command argumentAtIndex:2] integerValue];
- [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
+ [self readFileWithPath:localURI.fileSystemPath 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];
@@ -1257,19 +1320,17 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- (void)truncate:(CDVInvokedUrlCommand*)command
{
// arguments
- NSString* argPath = [command.arguments objectAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:[command argumentAtIndex:0]];
unsigned long long pos = (unsigned long long)[[command.arguments objectAtIndex:1] longLongValue];
// assets-library files can't be truncated
- if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
+ if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
return;
}
- NSString* appFile = argPath; // [self getFullPath:argPath];
-
- unsigned long long newPos = [self truncateFile:appFile atPosition:pos];
+ unsigned long long newPos = [self truncateFile:localURI.fileSystemPath atPosition:pos];
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:newPos];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
@@ -1293,7 +1354,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
/* write
* IN:
* NSArray* arguments
- * 0 - NSString* file path to write to
+ * 0 - NSString* localURI of file to write to
* 1 - NSString* or NSData* data to write
* 2 - NSNumber* position to begin writing
*/
@@ -1303,25 +1364,24 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
NSArray* arguments = command.arguments;
// arguments
- NSString* argPath = [arguments objectAtIndex:0];
+ NSString* localURIstr = [arguments objectAtIndex:0];
+ CDVFilesystemURL* localURI = [self fileSystemURLWithString:localURIstr];
id argData = [arguments objectAtIndex:1];
unsigned long long pos = (unsigned long long)[[arguments objectAtIndex:2] longLongValue];
// text can't be written into assets-library files
- if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
+ if ([[localURI.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
return;
}
- NSString* fullPath = argPath; // [self getFullPath:argPath];
-
- [self truncateFile:fullPath atPosition:pos];
+ [self truncateFile:localURI.fileSystemPath atPosition:pos];
if ([argData isKindOfClass:[NSString class]]) {
- [self writeToFile:fullPath withString:argData encoding:NSUTF8StringEncoding append:YES callback:callbackId];
+ [self writeToFile:localURI.fileSystemPath withString:argData encoding:NSUTF8StringEncoding append:YES callback:callbackId];
} else if ([argData isKindOfClass:[NSData class]]) {
- [self writeToFile:fullPath withData:argData append:YES callback:callbackId];
+ [self writeToFile:localURI.fileSystemPath withData:argData append:YES callback:callbackId];
} else {
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Invalid parameter type"];
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
@@ -1368,6 +1428,8 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
[self writeToFile:filePath withData:[stringData dataUsingEncoding:encoding allowLossyConversion:YES] append:shouldAppend callback:callbackId];
}
+#pragma mark Undocumented Filesystem API
+
- (void)testFileExists:(CDVInvokedUrlCommand*)command
{
// arguments
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/b3b6a83f/www/ios/FileSystem.js
----------------------------------------------------------------------
diff --git a/www/ios/FileSystem.js b/www/ios/FileSystem.js
new file mode 100644
index 0000000..2017e29
--- /dev/null
+++ b/www/ios/FileSystem.js
@@ -0,0 +1,27 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+module.exports = {
+ __format__: function(fullPath) {
+ return 'filesystem://localhost/'+this.name+(fullPath[0]==='/'?'':'/')+encodeURI(fullPath);
+ }
+};
+