You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/03/15 21:45:42 UTC

ios commit: [CB-2652] Make FileReader.readAs*() functions run on a background thread

Updated Branches:
  refs/heads/master b6e3bb46f -> f9ba26e3d


[CB-2652] Make FileReader.readAs*() functions run on a background thread

Also refactored to remove copy/paste.


Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/f9ba26e3
Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/f9ba26e3
Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/f9ba26e3

Branch: refs/heads/master
Commit: f9ba26e3da6fbc36c8ddd8c5bf7af4111e12e78a
Parents: b6e3bb4
Author: Andrew Grieve <ag...@chromium.org>
Authored: Mon Mar 11 22:09:16 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Fri Mar 15 16:44:07 2013 -0400

----------------------------------------------------------------------
 CordovaLib/Classes/CDVFile.h         |    1 +
 CordovaLib/Classes/CDVFile.m         |  305 +++++++++++------------------
 CordovaLib/Classes/CDVPluginResult.m |   10 +-
 3 files changed, 120 insertions(+), 196 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/f9ba26e3/CordovaLib/Classes/CDVFile.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFile.h b/CordovaLib/Classes/CDVFile.h
index e3fdc83..eaf8cbe 100644
--- a/CordovaLib/Classes/CDVFile.h
+++ b/CordovaLib/Classes/CDVFile.h
@@ -21,6 +21,7 @@
 #import "CDVPlugin.h"
 
 enum CDVFileError {
+    NO_ERROR = 0,
     NOT_FOUND_ERR = 1,
     SECURITY_ERR = 2,
     ABORT_ERR = 3,

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/f9ba26e3/CordovaLib/Classes/CDVFile.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFile.m b/CordovaLib/Classes/CDVFile.m
index e491ef8..bb12309 100644
--- a/CordovaLib/Classes/CDVFile.m
+++ b/CordovaLib/Classes/CDVFile.m
@@ -1053,238 +1053,161 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
 }
 
+- (void)readFileWithPath:(NSString*)path start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData *, NSString * mimeType, CDVFileError))callback
+{
+    if (path == nil) {
+        callback(nil, nil, SYNTAX_ERR);
+    } else {
+        [self.commandDelegate runInBackground:^ {
+                if ([path 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!  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];
+                } else {
+                    NSString* mimeType = [self 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);
+                }
+            }];
+    }
+}
+
 /* read and return file data
  * IN:
  * NSArray* arguments
  *	0 - NSString* fullPath
- *	1 - NSString* encoding - NOT USED,  iOS reads and writes using UTF8!
- *	2 - NSString* start - OPTIONAL, only provided when not == 0.
- *	3 - NSString* end - OPTIONAL, only provided when not == length.
+ *	1 - NSString* encoding
+ *	2 - NSString* start
+ *	3 - NSString* end
  */
 - (void)readAsText:(CDVInvokedUrlCommand*)command
 {
     // arguments
-    NSString* argPath = [command.arguments objectAtIndex:0];
-    NSInteger start = 0;
-    NSInteger end = -1;
-
-    if ([command.arguments count] >= 3) {
-        start = [[command.arguments objectAtIndex:2] integerValue];
-    }
-    if ([command.arguments count] >= 4) {
-        end = [[command.arguments objectAtIndex:3] integerValue];
+    NSString* path = [command argumentAtIndex:0];
+    NSString* encoding = [command argumentAtIndex:1];
+    NSInteger start = [[command argumentAtIndex:2] integerValue];
+    NSInteger end = [[command argumentAtIndex:3] integerValue];
+
+    // TODO: implement
+    if (![@"UTF-8" isEqualToString:encoding]) {
+        NSLog(@"Only UTF-8 encodings are currently supported by readAsText");
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR];
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        return;
     }
 
-    // NSString* encoding = [command.arguments objectAtIndex:2];   // not currently used
-    CDVPluginResult* result = nil;
-
-    NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:argPath];
-
-    if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        // can't read assets-library URLs as text
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
-    } else if (!file) {
-        // invalid path entry
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
-    } else {
-        if (start > 0) {
-            [file seekToFileOffset:start];
-        }
-
-        NSData* readData;
-        if (end < 0) {
-            readData = [file readDataToEndOfFile];
-        } else {
-            readData = [file readDataOfLength:(end - start)];
-        }
-
-        [file closeFile];
-        NSString* pNStrBuff = nil;
-        if (readData) {
-            pNStrBuff = [[NSString alloc] initWithBytes:[readData bytes] length:[readData length] encoding:NSUTF8StringEncoding];
-        } else {
-            // return empty string if no data
-            pNStrBuff = @"";
-        }
+    [self readFileWithPath:path start:start end:end callback:^(NSData * data, NSString * mimeType, CDVFileError errorCode) {
+            CDVPluginResult* result = nil;
+            if (data != nil) {
+                NSString* str = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSUTF8StringEncoding freeWhenDone:NO];
+                // Check that UTF8 conversion did not fail.
+                if (str != nil) {
+                    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:str];
+                    result.associatedObject = data;
+                } else {
+                    errorCode = ENCODING_ERR;
+                }
+            }
+            if (result == nil) {
+                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
+            }
 
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:pNStrBuff];
-    }
-    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        }];
 }
 
 /* Read content of text file and return as base64 encoded data url.
  * IN:
  * NSArray* arguments
  *	0 - NSString* fullPath
- *	1 - NSString* start - OPTIONAL, only provided when not == 0.
- *	2 - NSString* end - OPTIONAL, only provided when not == length.
+ *	1 - NSString* start
+ *	2 - NSString* end
  *
  * Determines the mime type from the file extension, returns ENCODING_ERR if mimetype can not be determined.
  */
 
 - (void)readAsDataURL:(CDVInvokedUrlCommand*)command
 {
-    // arguments
-    NSString* argPath = [command.arguments objectAtIndex:0];
-    NSInteger start = 0;
-    NSInteger end = -1;
-
-    if ([command.arguments count] >= 2) {
-        start = [[command.arguments objectAtIndex:1] integerValue];
-    }
-    if ([command.arguments count] >= 3) {
-        end = [[command.arguments objectAtIndex:2] integerValue];
-    }
-
-    CDVFileError errCode = ABORT_ERR;
-    __block CDVPluginResult* result = nil;
-
-    if (!argPath) {
-        errCode = SYNTAX_ERR;
-    } else if ([argPath 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!  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 = [self getMimeTypeFromPath:[assetRepresentation filename]];
-                NSString* dataString = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [data base64EncodedString]];
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:dataString];
-                [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 {
-        NSString* mimeType = [self getMimeTypeFromPath:argPath];
-        if (!mimeType) {
-            // can't return as data URL if can't figure out the mimeType
-            errCode = ENCODING_ERR;
-        } else {
-            NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:argPath];
-            if (start > 0) {
-                [file seekToFileOffset:start];
-            }
-
-            NSData* readData;
-            if (end < 0) {
-                readData = [file readDataToEndOfFile];
-            } else {
-                readData = [file readDataOfLength:(end - start)];
-            }
-
-            [file closeFile];
-            if (readData) {
-                NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [readData base64EncodedString]];
+    NSString* path = [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) {
+            CDVPluginResult* result = nil;
+            if (data != nil) {
+                // TODO: Would be faster to base64 encode directly to the final string.
+                NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [data base64EncodedString]];
                 result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output];
             } else {
-                errCode = NOT_FOUND_ERR;
+                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
             }
-        }
-    }
-    if (!result) {
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode];
-    }
-    // NSLog(@"readAsDataURL return: %@", jsString);
-    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+
+            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        }];
 }
 
 /* Read content of text file and return as an arraybuffer
  * IN:
  * NSArray* arguments
  *	0 - NSString* fullPath
- *	1 - NSString* start - OPTIONAL, only provided when not == 0.
- *	2 - NSString* end - OPTIONAL, only provided when not == length.
+ *	1 - NSString* start
+ *	2 - NSString* end
  */
 
 - (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command
 {
-    // arguments
-    NSString* argPath = [command.arguments objectAtIndex:0];
-    NSInteger start = 0;
-    NSInteger end = -1;
-
-    if ([command.arguments count] >= 2) {
-        start = [[command.arguments objectAtIndex:1] integerValue];
-    }
-    if ([command.arguments count] >= 3) {
-        end = [[command.arguments objectAtIndex:2] integerValue];
-    }
+    NSString* path = [command argumentAtIndex:0];
+    NSInteger start = [[command argumentAtIndex:1] integerValue];
+    NSInteger end = [[command argumentAtIndex:2] integerValue];
 
-    CDVFileError errCode = ABORT_ERR;
-    __block CDVPluginResult* result = nil;
-
-    if (!argPath) {
-        errCode = SYNTAX_ERR;
-    } else if ([argPath 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!  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];
+    [self readFileWithPath:path start:start end:end callback:^(NSData * data, NSString * mimeType, CDVFileError errorCode) {
+            CDVPluginResult* result = nil;
+            if (data != nil) {
                 result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data];
-                [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];
+                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
             }
-        };
-        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 {
-        NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:argPath];
-        if (start > 0) {
-            [file seekToFileOffset:start];
-        }
-
-        NSData* readData;
-        if (end < 0) {
-            readData = [file readDataToEndOfFile];
-        } else {
-            readData = [file readDataOfLength:(end - start)];
-        }
-
-        [file closeFile];
-        if (readData) {
-            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:readData];
-        } else {
-            errCode = NOT_FOUND_ERR;
-        }
-    }
-    if (!result) {
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode];
-    }
 
-    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        }];
 }
 
 /* helper function to get the mimeType from the file extension

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/f9ba26e3/CordovaLib/Classes/CDVPluginResult.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVPluginResult.m b/CordovaLib/Classes/CDVPluginResult.m
index ffc96a2..af7c528 100644
--- a/CordovaLib/Classes/CDVPluginResult.m
+++ b/CordovaLib/Classes/CDVPluginResult.m
@@ -35,10 +35,10 @@ static NSArray* org_apache_cordova_CommandStatusMsgs;
 
 id messageFromArrayBuffer(NSData* data)
 {
-    return @ {
+    return @{
                @"CDVType" : @"ArrayBuffer",
                @"data" :[data base64EncodedString]
-    }
+    };
 }
 
 id massageMessage(id message)
@@ -57,10 +57,10 @@ id messageFromMultipart(NSArray* theMessages)
         [messages replaceObjectAtIndex:i withObject:massageMessage([messages objectAtIndex:i])];
     }
 
-    return @ {
+    return @{
                @"CDVType" : @"MultiPart",
                @"messages" : messages
-    }
+    };
 }
 
 + (void)initialize
@@ -141,7 +141,7 @@ id messageFromMultipart(NSArray* theMessages)
 
 + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode
 {
-    NSDictionary* errDict = @ {@"code" :[NSNumber numberWithInt:errorCode]}
+    NSDictionary* errDict = @{@"code" :[NSNumber numberWithInt:errorCode]};
 
     return [[self alloc] initWithStatus:statusOrdinal message:errDict];
 }