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:38 UTC

[6/6] git commit: CB-5406: Split iOS file plugin into modules

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