diff options
Diffstat (limited to 'iPhone/CordovaLib/Classes/CDVFile.m')
-rwxr-xr-x | iPhone/CordovaLib/Classes/CDVFile.m | 341 |
1 files changed, 289 insertions, 52 deletions
diff --git a/iPhone/CordovaLib/Classes/CDVFile.m b/iPhone/CordovaLib/Classes/CDVFile.m index 1e5d009..d52405d 100755 --- a/iPhone/CordovaLib/Classes/CDVFile.m +++ b/iPhone/CordovaLib/Classes/CDVFile.m @@ -20,8 +20,11 @@ #import "CDVFile.h" #import "NSArray+Comparisons.h" #import "NSDictionary+Extensions.h" -#import "JSONKit.h" +#import "CDVJSON.h" #import "NSData+Base64.h" +#import <AssetsLibrary/ALAsset.h> +#import <AssetsLibrary/ALAssetRepresentation.h> +#import <AssetsLibrary/ALAssetsLibrary.h> #import <MobileCoreServices/MobileCoreServices.h> #import "CDVAvailability.h" #import "sys/xattr.h" @@ -32,6 +35,8 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) NSString* const NSURLIsExcludedFromBackupKey = @"NSURLIsExcludedFromBackupKey"; #endif +NSString* const kCDVAssetsLibraryPrefix = @"assets-library://"; + @implementation CDVFile @synthesize appDocsPath, appLibraryPath, appTempPath, persistentPath, temporaryPath, userHasAllowed; @@ -329,6 +334,13 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) 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]) { + 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; @@ -425,6 +437,13 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) // arguments are URL encoded NSString* fullPath = [command.arguments objectAtIndex:0]; + // we don't (yet?) support getting the parent of an asset + if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { + 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; @@ -461,11 +480,40 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) { // arguments NSString* argPath = [command.arguments objectAtIndex:0]; + __block CDVPluginResult* result = nil; + + 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! 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:argPath] resultBlock:resultBlock failureBlock:failureBlock]; + return; + } + NSString* testPath = argPath; // [self getFullPath: argPath]; NSFileManager* fileMgr = [[NSFileManager alloc] init]; NSError* __autoreleasing error = nil; - CDVPluginResult* result = nil; NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:testPath error:&error]; @@ -477,7 +525,7 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) } else { // didn't get fileAttribs CDVFileError errorCode = ABORT_ERR; - NSLog(@"error getting metadata: %@", [error localizedDescription]); + NSLog (@"error getting metadata: %@", [error localizedDescription]); if ([error code] == NSFileNoSuchFileError) { errorCode = NOT_FOUND_ERR; } @@ -500,27 +548,29 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) // arguments NSString* filePath = [command.arguments objectAtIndex:0]; NSDictionary* options = [command.arguments objectAtIndex:1 withDefault:nil]; - CDVPluginResult* result = nil; BOOL ok = NO; - // 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); + // setMetadata doesn't make sense for asset library files + if (![filePath hasPrefix:kCDVAssetsLibraryPrefix]) { + // 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); + } } } } @@ -539,19 +589,21 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) * 0 - NSString* fullPath * * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir - * returns INVALID_MODIFICATION_ERR if is dir and is not empty + * returns INVALID_MODIFICATION_ERR if is non-empty dir or asset library file * returns NOT_FOUND_ERR if file or dir is not found */ - (void)remove:(CDVInvokedUrlCommand*)command { // arguments NSString* fullPath = [command.arguments objectAtIndex:0]; - CDVPluginResult* result = nil; CDVFileError errorCode = 0; // !! 0 not currently defined - // error if try to remove top level (documents or tmp) dir - if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) { + // return error for assets-library URLs + if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { + errorCode = INVALID_MODIFICATION_ERR; + } else if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) { + // error if try to remove top level (documents or tmp) dir errorCode = NO_MODIFICATION_ALLOWED_ERR; } else { NSFileManager* fileMgr = [[NSFileManager alloc] init]; @@ -587,6 +639,13 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) // arguments NSString* fullPath = [command.arguments objectAtIndex:0]; + // return unsupported result for assets-library URLs + if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { + 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 @@ -693,7 +752,7 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) // optional argument NSString* newName = ([arguments count] > 2) ? [arguments objectAtIndex:2] : [srcFullPath lastPathComponent]; // use last component from appPath if new name not provided - CDVPluginResult* result = nil; + __block CDVPluginResult* result = nil; CDVFileError errCode = 0; // !! Currently 0 is not defined, use this to signal error !! /*NSString* destRootPath = nil; @@ -710,12 +769,59 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) errCode = ENCODING_ERR; } else { NSString* newFullPath = [destRootPath stringByAppendingPathComponent:newName]; + NSFileManager* fileMgr = [[NSFileManager alloc] init]; if ([newFullPath isEqualToString:srcFullPath]) { // source and destination can not be the same errCode = INVALID_MODIFICATION_ERR; - } else { - NSFileManager* fileMgr = [[NSFileManager alloc] init]; + } else if ([srcFullPath hasPrefix:kCDVAssetsLibraryPrefix]) { + 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:newFullPath]) { + // 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; + } + // 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:newFullPath atomically:YES]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:newFullPath 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; @@ -838,30 +944,67 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) // arguments NSString* argPath = [command.arguments objectAtIndex:0]; - CDVPluginResult* result = nil; + __block CDVPluginResult* result = nil; NSString* fullPath = argPath; // [self getFullPath: argPath]; if (fullPath) { - 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]; + 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 { - // create dictionary of file info - NSError* __autoreleasing error = nil; - NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:&error]; - 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]; - [fileInfo setObject:msDate forKey:@"lastModifiedDate"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]; + 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]; + 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]; + [fileInfo setObject:msDate forKey:@"lastModifiedDate"]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]; + } } } if (!result) { @@ -875,6 +1018,13 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) // arguments NSString* fullPath = [command.arguments objectAtIndex:0]; + // 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."]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + return; + } + CDVPluginResult* result = nil; NSFileManager* fileMgr = [[NSFileManager alloc] init]; @@ -908,21 +1058,45 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) * 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. */ - (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* encoding = [command.arguments objectAtIndex:2]; // not currently used CDVPluginResult* result = nil; NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:argPath]; - if (!file) { + 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 { - NSData* readData = [file readDataToEndOfFile]; + 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; @@ -933,7 +1107,7 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) pNStrBuff = @""; } - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[pNStrBuff stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:pNStrBuff]; } [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; } @@ -950,12 +1124,51 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) { // 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; - CDVPluginResult* result = nil; + __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) { @@ -963,7 +1176,17 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) errCode = ENCODING_ERR; } else { NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:argPath]; - NSData* readData = [file readDataToEndOfFile]; + 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]]; @@ -1014,6 +1237,13 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) NSString* argPath = [command.arguments objectAtIndex:0]; unsigned long long pos = (unsigned long long)[[command.arguments objectAtIndex:1] longLongValue]; + // assets-library files can't be truncated + if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) { + 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]; @@ -1054,6 +1284,13 @@ extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import) NSString* 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]) { + 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]; |