You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/03/25 22:53:26 UTC

[3/6] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
index d52405d..8c65270 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
@@ -52,7 +52,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
         paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
         self.appLibraryPath = [paths objectAtIndex:0];
 
-        self.appTempPath = [NSTemporaryDirectory ()stringByStandardizingPath];  // remove trailing slash from NSTemporaryDirectory()
+        self.appTempPath = [NSTemporaryDirectory()stringByStandardizingPath];   // remove trailing slash from NSTemporaryDirectory()
 
         self.persistentPath = [NSString stringWithFormat:@"/%@", [self.appDocsPath lastPathComponent]];
         self.temporaryPath = [NSString stringWithFormat:@"/%@", [self.appTempPath lastPathComponent]];
@@ -164,7 +164,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:QUOTA_EXCEEDED_ERR];
         } else {
             NSMutableDictionary* fileSystem = [NSMutableDictionary dictionaryWithCapacity:2];
-            [fileSystem setObject:(type == TEMPORARY ? kW3FileTemporary:kW3FilePersistent) forKey:@"name"];
+            [fileSystem setObject:(type == TEMPORARY ? kW3FileTemporary : kW3FilePersistent) forKey:@"name"];
             NSDictionary* dirEntry = [self getDirectoryEntry:fullPath isDirectory:YES];
             [fileSystem setObject:dirEntry forKey:@"root"];
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
@@ -486,7 +486,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
         // In this case, we need to use an asynchronous method to retrieve the file.
         // Because of this, we can't just assign to `result` and send it at the end of the method.
         // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
-        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
             if (asset) {
                 // We have the asset!  Retrieve the metadata and send it off.
                 NSDate* date = [asset valueForProperty:ALAssetPropertyDate];
@@ -499,7 +499,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             }
         };
         // TODO(maxw): Consider making this a class variable since it's the same every time.
-        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+        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];
@@ -525,7 +525,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     } 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;
         }
@@ -779,7 +779,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
                 // In this case, we need to use an asynchronous method to retrieve the file.
                 // Because of this, we can't just assign to `result` and send it at the end of the method.
                 // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
-                ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+                ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
                     if (asset) {
                         // We have the asset!  Get the data and try to copy it over.
                         if (![fileMgr fileExistsAtPath:destRootPath]) {
@@ -796,7 +796,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
 
                         // We're good to go!  Write the file to the new destination.
                         ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
-                        Byte* buffer = (Byte*)malloc ([assetRepresentation size]);
+                        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];
@@ -808,7 +808,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
                         [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
                     }
                 };
-                ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+                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];
@@ -953,7 +953,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             // In this case, we need to use an asynchronous method to retrieve the file.
             // Because of this, we can't just assign to `result` and send it at the end of the method.
             // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
-            ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+            ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
                 if (asset) {
                     // We have the asset!  Populate the dictionary and send it off.
                     NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
@@ -975,7 +975,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
                     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
                 }
             };
-            ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+            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];
@@ -1053,154 +1053,181 @@ 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)];
+    [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;
+            }
         }
-
-        [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 = @"";
+        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
+ *	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];
-    }
+    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 {
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
+        }
 
-    CDVFileError errCode = ABORT_ERR;
-    __block CDVPluginResult* result = nil;
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+    }];
+}
 
-    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];
-        };
+/* Read content of text file and return as an arraybuffer
+ * IN:
+ * NSArray* arguments
+ *	0 - NSString* fullPath
+ *	1 - NSString* start
+ *	2 - NSString* end
+ */
 
-        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;
+- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command
+{
+    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) {
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data];
         } else {
-            NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:argPath];
-            if (start > 0) {
-                [file seekToFileOffset:start];
-            }
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
+        }
 
-            NSData* readData;
-            if (end < 0) {
-                readData = [file readDataToEndOfFile];
-            } else {
-                readData = [file readDataOfLength:(end - start)];
-            }
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+    }];
+}
 
-            [file closeFile];
-            if (readData) {
-                NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [readData base64EncodedString]];
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output];
-            } else {
-                errCode = NOT_FOUND_ERR;
-            }
+- (void)readAsBinaryString:(CDVInvokedUrlCommand*)command
+{
+    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) {
+            NSString* payload = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSASCIIStringEncoding freeWhenDone:NO];
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload];
+            result.associatedObject = data;
+        } else {
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
         }
-    }
-    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];
+    }];
 }
 
 /* helper function to get the mimeType from the file extension
@@ -1219,7 +1246,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType);
             if (!mimeType) {
                 // special case for m4a
-                if ([(__bridge NSString*) typeId rangeOfString:@"m4a-audio"].location != NSNotFound) {
+                if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) {
                     mimeType = @"audio/mp4";
                 } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) {
                     mimeType = @"audio/wav";
@@ -1343,7 +1370,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     NSString* appFile = argPath; // [ self getFullPath: argPath];
 
     BOOL bExists = [fMgr fileExistsAtPath:appFile];
-    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1:0)];
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1 : 0)];
 
     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
 }
@@ -1359,7 +1386,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     BOOL bIsDir = NO;
     BOOL bExists = [fMgr fileExistsAtPath:appFile isDirectory:&bIsDir];
 
-    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1:0)];
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1 : 0)];
 
     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
index f96bb7d..d82cdd3 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
@@ -48,10 +48,10 @@ extern NSString* const kOptionsKeyCookie;
 - (NSMutableDictionary*)createFileTransferError:(int)code AndSource:(NSString*)source AndTarget:(NSString*)target;
 
 - (NSMutableDictionary*)createFileTransferError:(int)code
-       AndSource                                   :(NSString*)source
-       AndTarget                                   :(NSString*)target
-   AndHttpStatus                               :(int)httpStatus
-         AndBody                                     :(NSString*)body;
+                                      AndSource:(NSString*)source
+                                      AndTarget:(NSString*)target
+                                  AndHttpStatus:(int)httpStatus
+                                        AndBody:(NSString*)body;
 @property (readonly) NSMutableDictionary* activeTransfers;
 @end
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
index 4ccdce6..5741aca 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
@@ -52,8 +52,8 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 
     while (totalBytesWritten < bytesToWrite) {
         CFIndex result = CFWriteStreamWrite(stream,
-            bytes + totalBytesWritten,
-            bytesToWrite - totalBytesWritten);
+                bytes + totalBytesWritten,
+                bytesToWrite - totalBytesWritten);
         if (result < 0) {
             CFStreamError error = CFWriteStreamGetError(stream);
             NSLog(@"WriteStreamError domain: %ld error: %ld", error.domain, error.error);
@@ -190,7 +190,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         [postBodyBeforeFile appendData:formBoundaryData];
         [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
         [postBodyBeforeFile appendData:[val dataUsingEncoding:NSUTF8StringEncoding]];
-        [postBodyBeforeFile appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
+        [postBodyBeforeFile appendData:[@"\r\n" dataUsingEncoding : NSUTF8StringEncoding]];
     }
 
     [postBodyBeforeFile appendData:formBoundaryData];
@@ -213,22 +213,22 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         [req setHTTPBodyStream:CFBridgingRelease(readStream)];
 
         [self.commandDelegate runInBackground:^{
-                if (CFWriteStreamOpen (writeStream)) {
-                    NSData* chunks[] = {postBodyBeforeFile, fileData, postBodyAfterFile};
-                    int numChunks = sizeof (chunks) / sizeof (chunks[0]);
-
-                    for (int i = 0; i < numChunks; ++i) {
-                        CFIndex result = WriteDataToStream (chunks[i], writeStream);
-                        if (result <= 0) {
-                            break;
-                        }
+            if (CFWriteStreamOpen(writeStream)) {
+                NSData* chunks[] = {postBodyBeforeFile, fileData, postBodyAfterFile};
+                int numChunks = sizeof(chunks) / sizeof(chunks[0]);
+
+                for (int i = 0; i < numChunks; ++i) {
+                    CFIndex result = WriteDataToStream(chunks[i], writeStream);
+                    if (result <= 0) {
+                        break;
                     }
-                } else {
-                    NSLog (@"FileTransfer: Failed to open writeStream");
                 }
-                CFWriteStreamClose (writeStream);
-                CFRelease (writeStream);
-            }];
+            } else {
+                NSLog(@"FileTransfer: Failed to open writeStream");
+            }
+            CFWriteStreamClose(writeStream);
+            CFRelease(writeStream);
+        }];
     } else {
         [postBodyBeforeFile appendData:fileData];
         [postBodyBeforeFile appendData:postBodyAfterFile];
@@ -265,11 +265,11 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     // return unsupported result for assets-library URLs
     if ([target hasPrefix:kCDVAssetsLibraryPrefix]) {
         // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
-        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+        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]);
+                Byte* buffer = (Byte*)malloc([assetRepresentation size]);
                 NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
                 NSData* fileData = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
                 [self uploadData:fileData command:command];
@@ -279,7 +279,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
                 [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
             }
         };
-        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
             // Retrieving the asset failed for some reason.  Send the appropriate error.
             CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
             [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
@@ -291,12 +291,18 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     } else {
         // Extract the path part out of a file: URL.
         NSString* filePath = [target hasPrefix:@"/"] ? [target copy] : [[NSURL URLWithString:target] path];
+        if (filePath == nil) {
+            // We couldn't find the asset.  Send the appropriate error.
+            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+            return;
+        }
 
         // Memory map the file so that it can be read efficiently even if it is large.
         NSData* fileData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&err];
 
         if (err != nil) {
-            NSLog (@"Error opening file %@: %@", target, err);
+            NSLog(@"Error opening file %@: %@", target, err);
         }
         [self uploadData:fileData command:command];
     }
@@ -352,6 +358,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     NSString* filePath = [command.arguments objectAtIndex:1];
     BOOL trustAllHosts = [[command.arguments objectAtIndex:2 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs
     NSString* objectId = [command.arguments objectAtIndex:3];
+    NSDictionary* headers = [command.arguments objectAtIndex:4 withDefault:nil];
 
     // return unsupported result for assets-library URLs
     if ([filePath hasPrefix:kCDVAssetsLibraryPrefix]) {
@@ -388,7 +395,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     }
 
     NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
-    [self applyRequestHeaders:nil toRequest:req];
+    [self applyRequestHeaders:headers toRequest:req];
 
     CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init];
     delegate.command = self;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m b/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
index 4d960cd..9eb9721 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
@@ -138,14 +138,14 @@
 
     // create the formatter using the user's current default locale and formats for dates and times
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        dateStyle,
-        timeStyle);
+            currentLocale,
+            dateStyle,
+            timeStyle);
     // if we have a valid date object then call the formatter
     if (date) {
         dateString = (__bridge_transfer NSString*)CFDateFormatterCreateStringWithDate(kCFAllocatorDefault,
-            formatter,
-            (__bridge CFDateRef)date);
+                formatter,
+                (__bridge CFDateRef)date);
     }
 
     // if the date was converted to a string successfully then return the result
@@ -227,18 +227,18 @@
 
     // get the user's default settings for date and time formats
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        dateStyle,
-        timeStyle);
+            currentLocale,
+            dateStyle,
+            timeStyle);
 
     // set the parsing to be more lenient
     CFDateFormatterSetProperty(formatter, kCFDateFormatterIsLenient, kCFBooleanTrue);
 
     // parse tha date and time string
     CFDateRef date = CFDateFormatterCreateDateFromString(kCFAllocatorDefault,
-        formatter,
-        (__bridge CFStringRef)dateString,
-        NULL);
+            formatter,
+            (__bridge CFStringRef)dateString,
+            NULL);
 
     // if we were able to parse the date then get the date and time components
     if (date != NULL) {
@@ -336,9 +336,9 @@
 
     // get the user's default settings for date and time formats
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        dateStyle,
-        timeStyle);
+            currentLocale,
+            dateStyle,
+            timeStyle);
 
     // get the date pattern to apply when formatting and parsing
     CFStringRef datePattern = CFDateFormatterGetFormat(formatter);
@@ -415,9 +415,9 @@
     }
 
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        kCFDateFormatterFullStyle,
-        kCFDateFormatterFullStyle);
+            currentLocale,
+            kCFDateFormatterFullStyle,
+            kCFDateFormatterFullStyle);
 
     if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_LONG)) {
         dataStyle = kCFDateFormatterMonthSymbols;
@@ -545,13 +545,13 @@
     }
 
     CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        style);
+            currentLocale,
+            style);
 
     // get the localized string based upon the locale and user preferences
     NSString* numberString = (__bridge_transfer NSString*)CFNumberFormatterCreateStringWithNumber(kCFAllocatorDefault,
-        formatter,
-        (__bridge CFNumberRef)number);
+            formatter,
+            (__bridge CFNumberRef)number);
 
     if (numberString) {
         NSDictionary* dictionary = [NSDictionary dictionaryWithObject:numberString forKey:@"value"];
@@ -612,8 +612,8 @@
     }
 
     CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        style);
+            currentLocale,
+            style);
 
     // we need to make this lenient so as to avoid problems with parsing currencies that have non-breaking space characters
     if (style == kCFNumberFormatterCurrencyStyle) {
@@ -622,10 +622,10 @@
 
     // parse againist the largest type to avoid data loss
     Boolean rc = CFNumberFormatterGetValueFromString(formatter,
-        (__bridge CFStringRef)numberString,
-        NULL,
-        kCFNumberDoubleType,
-        &doubleValue);
+            (__bridge CFStringRef)numberString,
+            NULL,
+            kCFNumberDoubleType,
+            &doubleValue);
 
     if (rc) {
         NSDictionary* dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:doubleValue] forKey:@"value"];
@@ -681,8 +681,8 @@
     }
 
     CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        style);
+            currentLocale,
+            style);
 
     NSString* numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter);
 
@@ -749,8 +749,8 @@
     // now set the currency code in the formatter
     if (rc) {
         CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-            currentLocale,
-            kCFNumberFormatterCurrencyStyle);
+                currentLocale,
+                kCFNumberFormatterCurrencyStyle);
 
         CFNumberFormatterSetProperty(formatter, kCFNumberFormatterCurrencyCode, (__bridge CFStringRef)currencyCode);
         CFNumberFormatterSetProperty(formatter, kCFNumberFormatterInternationalCurrencySymbol, (__bridge CFStringRef)currencyCode);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
index 9ff460a..f63250a 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
@@ -20,6 +20,7 @@
 #import "CDVPlugin.h"
 #import "CDVInvokedUrlCommand.h"
 #import "CDVScreenOrientationDelegate.h"
+#import "CDVWebViewDelegate.h"
 
 @class CDVInAppBrowserViewController;
 
@@ -27,6 +28,7 @@
 
 - (void)browserLoadStart:(NSURL*)url;
 - (void)browserLoadStop:(NSURL*)url;
+- (void)browserLoadError:(NSError*)error forUrl:(NSURL*)url;
 - (void)browserExit;
 
 @end
@@ -47,6 +49,7 @@
     NSString* _userAgent;
     NSString* _prevUserAgent;
     NSInteger _userAgentLockToken;
+    CDVWebViewDelegate* _webViewDelegate;
 }
 
 @property (nonatomic, strong) IBOutlet UIWebView* webView;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
index 14671a5..d001dfd 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
@@ -165,7 +165,7 @@
 {
     if (self.callbackId != nil) {
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@ {@"type":@"loadstart", @"url":[url absoluteString]}];
+                                                      messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -176,7 +176,18 @@
 {
     if (self.callbackId != nil) {
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@ {@"type":@"loadstop", @"url":[url absoluteString]}];
+                                                      messageAsDictionary:@{@"type":@"loadstop", @"url":[url absoluteString]}];
+        [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
+
+        [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
+    }
+}
+
+- (void)browserLoadError:(NSError*)error forUrl:(NSURL*)url
+{
+    if (self.callbackId != nil) {
+        CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
+                                                      messageAsDictionary:@{@"type":@"loaderror", @"url":[url absoluteString], @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -187,7 +198,7 @@
 {
     if (self.callbackId != nil) {
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@ {@"type":@"exit"}];
+                                                      messageAsDictionary:@{@"type":@"exit"}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -209,6 +220,7 @@
     if (self != nil) {
         _userAgent = userAgent;
         _prevUserAgent = prevUserAgent;
+        _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self];
         [self createViews];
     }
 
@@ -229,7 +241,7 @@
     [self.view addSubview:self.webView];
     [self.view sendSubviewToBack:self.webView];
 
-    self.webView.delegate = self;
+    self.webView.delegate = _webViewDelegate;
     self.webView.backgroundColor = [UIColor whiteColor];
 
     self.webView.clearsContextBeforeDrawing = YES;
@@ -391,10 +403,10 @@
         [self.webView loadRequest:request];
     } else {
         [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
-                _userAgentLockToken = lockToken;
-                [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken];
-                [self.webView loadRequest:request];
-            }];
+            _userAgentLockToken = lockToken;
+            [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken];
+            [self.webView loadRequest:request];
+        }];
     }
 }
 
@@ -419,14 +431,18 @@
     self.forwardButton.enabled = theWebView.canGoForward;
 
     [self.spinner startAnimating];
+}
 
+- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
+{
     if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStart:)]) {
-        NSURL* url = theWebView.request.URL;
+        NSURL* url = request.URL;
         if (url == nil) {
             url = _requestedURL;
         }
         [self.navigationDelegate browserLoadStart:url];
     }
+    return YES;
 }
 
 - (void)webViewDidFinishLoad:(UIWebView*)theWebView
@@ -450,7 +466,7 @@
     //    from it must pass through its white-list. This *does* break PDFs that
     //    contain links to other remote PDF/websites.
     // More info at https://issues.apache.org/jira/browse/CB-2225
-    BOOL isPDF = [@"true" isEqualToString:[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]];
+    BOOL isPDF = [@"true" isEqualToString :[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]];
     if (isPDF) {
         [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken];
     }
@@ -471,6 +487,11 @@
     [self.spinner stopAnimating];
 
     self.addressLabel.text = @"Load Error";
+
+    if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadError:forUrl:)]) {
+        NSURL* url = theWebView.request.URL;
+        [self.navigationDelegate browserLoadError:error forUrl:url];
+    }
 }
 
 #pragma mark CDVScreenOrientationDelegate

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h b/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
index 6eb0099..7be8884 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
@@ -34,9 +34,9 @@
 + (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry;
 
 - (id)initWithArguments:(NSArray*)arguments
-   callbackId          :(NSString*)callbackId
-    className           :(NSString*)className
-   methodName          :(NSString*)methodName;
+             callbackId:(NSString*)callbackId
+              className:(NSString*)className
+             methodName:(NSString*)methodName;
 
 - (id)initFromJson:(NSArray*)jsonEntry;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
new file mode 100644
index 0000000..02fe91f
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
@@ -0,0 +1,60 @@
+/*
+ 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 <Foundation/Foundation.h>
+
+@interface CDVJpegHeaderWriter : NSObject {
+    NSDictionary * SubIFDTagFormatDict;
+    NSDictionary * IFD0TagFormatDict;
+}
+
+- (NSString*) createExifAPP1 : (NSDictionary*) datadict;
+- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb 
+                                       withPlaces: (NSNumber*) width;
+- (NSString*) formatNumberWithLeadingZeroes: (NSNumber*) numb 
+                                 withPlaces: (NSNumber*) places;
+- (NSString*) decimalToUnsignedRational: (NSNumber*) numb
+                    withResultNumerator: (NSNumber**) numerator
+                  withResultDenominator: (NSNumber**) denominator;
+- (void) continuedFraction: (double) val
+          withFractionList: (NSMutableArray*) fractionlist 
+               withHorizon: (int) horizon;
+//- (void) expandContinuedFraction: (NSArray*) fractionlist;
+- (void) splitDouble: (double) val 
+         withIntComponent: (int*) rightside 
+         withFloatRemainder: (double*) leftside;
+- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator
+                          withDenominator: (NSNumber*) denominator
+                               asSigned: (Boolean) signedFlag;
+- (NSString*) hexStringFromData : (NSData*) data;
+- (NSNumber*) numericFromHexString : (NSString *) hexstring;
+
+/*
+- (void) readExifMetaData : (NSData*) imgdata;
+- (void) spliceImageData : (NSData*) imgdata withExifData: (NSDictionary*) exifdata;
+- (void) locateExifMetaData : (NSData*) imgdata;
+- (NSString*) createExifAPP1 : (NSDictionary*) datadict;
+- (void) createExifDataString : (NSDictionary*) datadict;
+- (NSString*) createDataElement : (NSString*) element
+              withElementData: (NSString*) data
+              withExternalDataBlock: (NSDictionary*) memblock;
+- (NSString*) hexStringFromData : (NSData*) data;
+- (NSNumber*) numericFromHexString : (NSString *) hexstring;
+*/
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
new file mode 100644
index 0000000..7b59d11
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
@@ -0,0 +1,472 @@
+/*
+ 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 "CDVJpegHeaderWriter.h"
+#include "CDVExif.h"
+
+// tag info shorthand, tagno: tag number, typecode: data type:, components: number of components
+#define TAGINF(tagno, typecode, components) [NSArray arrayWithObjects: tagno, typecode, components, nil]
+
+const uint mJpegId = 0xffd8; // JPEG format marker
+const uint mExifMarker = 0xffe1; // APP1 jpeg header marker
+const uint mExif = 0x45786966; // ASCII 'Exif', first characters of valid exif header after size
+const uint mMotorallaByteAlign = 0x4d4d; // 'MM', motorola byte align, msb first or 'sane'
+const uint mIntelByteAlgin = 0x4949; // 'II', Intel byte align, lsb first or 'batshit crazy reverso world'
+const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a(MM) or 0x2a00(II), tiff version number
+
+
+@implementation CDVJpegHeaderWriter
+
+- (id) init {    
+    self = [super init];
+    // supported tags for exif IFD
+    IFD0TagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys:
+                  //      TAGINF(@"010e", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"ImageDescription",
+                        TAGINF(@"0132", [NSNumber numberWithInt:EDT_ASCII_STRING], @20), @"DateTime",
+                        TAGINF(@"010f", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Make",
+                        TAGINF(@"0110", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Model",
+                        TAGINF(@"0131", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Software",
+                        TAGINF(@"011a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"XResolution",
+                        TAGINF(@"011b", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"YResolution",
+                        // currently supplied outside of Exif data block by UIImagePickerControllerMediaMetadata, this is set manually in CDVCamera.m
+                        TAGINF(@"0112", [NSNumber numberWithInt:EDT_USHORT], @1), @"Orientation",
+                       
+                        // rest of the tags are supported by exif spec, but are not specified by UIImagePickerControllerMediaMedadata
+                        // should camera hardware supply these values in future versions, or if they can be derived, ImageHeaderWriter will include them gracefully
+                        TAGINF(@"0128", [NSNumber numberWithInt:EDT_USHORT], @1), @"ResolutionUnit",
+                        TAGINF(@"013e", [NSNumber numberWithInt:EDT_URATIONAL], @2), @"WhitePoint",
+                        TAGINF(@"013f", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"PrimaryChromaticities",
+                        TAGINF(@"0211", [NSNumber numberWithInt:EDT_URATIONAL], @3), @"YCbCrCoefficients",
+                        TAGINF(@"0213", [NSNumber numberWithInt:EDT_USHORT], @1), @"YCbCrPositioning",
+                        TAGINF(@"0214", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"ReferenceBlackWhite",
+                        TAGINF(@"8298", [NSNumber numberWithInt:EDT_URATIONAL], @0), @"Copyright",
+                         
+                        // offset to exif subifd, we determine this dynamically based on the size of the main exif IFD
+                        TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",
+                        nil];
+
+    // supported tages for exif subIFD
+    SubIFDTagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys:
+                          // TAGINF(@"9000", [NSNumber numberWithInt:], @), @"ExifVersion",
+                           // TAGINF(@"9202",[NSNumber numberWithInt:EDT_URATIONAL],@1), @"ApertureValue",
+                           // TAGINF(@"9203",[NSNumber numberWithInt:EDT_SRATIONAL],@1), @"BrightnessValue",
+                           TAGINF(@"a001",[NSNumber numberWithInt:EDT_USHORT],@1), @"ColorSpace",
+                           TAGINF(@"9004",[NSNumber numberWithInt:EDT_ASCII_STRING],@20), @"DateTimeDigitized",
+                           TAGINF(@"9003",[NSNumber numberWithInt:EDT_ASCII_STRING],@20), @"DateTimeOriginal",
+                           TAGINF(@"a402", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureMode",
+                           TAGINF(@"8822", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureProgram",
+                           TAGINF(@"829a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"ExposureTime",
+                           TAGINF(@"829d", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FNumber",
+                           TAGINF(@"9209", [NSNumber numberWithInt:EDT_USHORT], @1), @"Flash",
+                           // FocalLengthIn35mmFilm
+                           TAGINF(@"a405", [NSNumber numberWithInt:EDT_USHORT], @1), @"FocalLenIn35mmFilm",
+                           TAGINF(@"920a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FocalLength",
+
+                           //TAGINF(@"8827", [NSNumber numberWithInt:EDT_USHORT], @2), @"ISOSpeedRatings",
+
+                           TAGINF(@"9207",[NSNumber numberWithInt:EDT_USHORT],@1), @"MeteringMode",
+                           // specific to compressed data
+                           TAGINF(@"a002", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelXDimension",
+                           TAGINF(@"a003", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelYDimension",
+                           // data type undefined, but this is a DSC camera, so value is always 1, treat as ushort
+                           TAGINF(@"a301", [NSNumber numberWithInt:EDT_USHORT],@1), @"SceneType",
+                           TAGINF(@"a217",[NSNumber numberWithInt:EDT_USHORT],@1), @"SensingMethod",
+                    // TAGINF(@"9201", [NSNumber numberWithInt:EDT_SRATIONAL], @1), @"ShutterSpeedValue",
+                           // specifies location of main subject in scene (x,y,wdith,height) expressed before rotation processing
+                           // TAGINF(@"9214", [NSNumber numberWithInt:EDT_USHORT], @4), @"SubjectArea",
+                           TAGINF(@"a403", [NSNumber numberWithInt:EDT_USHORT], @1), @"WhiteBalance",
+                      nil];
+    return self;
+}
+
+/**
+ * Create the Exif data block as a hex string
+ *   jpeg uses Application Markers (APP's) as markers for application data
+ *   APP1 is the application marker reserved for exif data
+ *
+ *   (NSDictionary*) datadict - with subdictionaries marked '{TIFF}' and '{EXIF}' as returned by imagePickerController with a valid
+ *                              didFinishPickingMediaWithInfo data dict, under key @"UIImagePickerControllerMediaMetadata"
+ *
+ *   the following constructs a hex string to Exif specifications, and is therefore brittle
+ *   altering the order of arguments to the string constructors, modifying field sizes or formats,
+ *   and any other minor change will likely prevent the exif data from being read
+ */
+- (NSString*) createExifAPP1 : (NSDictionary*) datadict {
+    NSMutableString * app1; // holds finalized product
+    NSString * exifIFD; // exif information file directory
+    NSString * subExifIFD; // subexif information file directory
+    
+    // FFE1 is the hex APP1 marker code, and will allow client apps to read the data
+    NSString * app1marker = @"ffe1";
+    // SSSS size, to be determined
+    // EXIF ascii characters followed by 2bytes of zeros
+    NSString * exifmarker = @"457869660000";
+    // Tiff header: 4d4d is motorolla byte align (big endian), 002a is hex for 42
+    NSString * tiffheader = @"4d4d002a";
+    //first IFD offset from the Tiff header to IFD0. Since we are writing it, we know it's address 0x08
+    NSString * ifd0offset = @"00000008";
+    
+    //data labeled as TIFF in UIImagePickerControllerMediaMetaData is part of the EXIF IFD0 portion of APP1
+    exifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{TIFF}"] withFormatDict: IFD0TagFormatDict isIFD0:YES];
+
+    //data labeled as EXIF in UIImagePickerControllerMediaMetaData is part of the EXIF Sub IFD portion of APP1
+    subExifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{Exif}"] withFormatDict: SubIFDTagFormatDict isIFD0:NO];
+
+    // construct the complete app1 data block
+    app1 = [[NSMutableString alloc] initWithFormat: @"%@%04x%@%@%@%@%@",
+            app1marker,
+            16+[exifIFD length]/2+[subExifIFD length]/2/*16+[exifIFD length]/2*/,
+            exifmarker,
+            tiffheader,
+            ifd0offset,
+            exifIFD,
+            subExifIFD];
+     
+    return app1;
+}
+
+// returns hex string representing a valid exif information file directory constructed from the datadict and formatdict
+- (NSString*) createExifIFDFromDict : (NSDictionary*) datadict withFormatDict : (NSDictionary*) formatdict isIFD0 : (BOOL) ifd0flag {
+    NSArray * datakeys = [datadict allKeys]; // all known data keys 
+    NSArray * knownkeys = [formatdict  allKeys]; // only keys in knowkeys are considered for entry in this IFD
+    NSMutableArray * ifdblock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // all ifd entries
+    NSMutableArray * ifddatablock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // data block entries
+    ifd0flag = NO; // ifd0 requires a special flag and has offset to next ifd appended to end
+    
+    // iterate through known provided data keys
+    for (int i = 0; i < [datakeys count]; i++) {
+        NSString * key = [datakeys objectAtIndex:i];
+        // don't muck about with unknown keys
+        if ([knownkeys indexOfObject: key] != NSNotFound) {
+            // create new IFD entry
+            NSString * entry = [self  createIFDElement: key
+                                      withFormatDict: formatdict
+                                      withElementData: [datadict objectForKey:key]];
+            // create the IFD entry's data block
+            NSString * data = [self createIFDElementDataWithFormat: [formatdict objectForKey:key]
+                                                   withData: [datadict objectForKey:key]];
+            if (entry) {
+                [ifdblock addObject:entry];
+                if(!data) {
+                    [ifdblock addObject:@""];
+                } else {
+                    [ifddatablock addObject:data];
+                }
+            }
+        }
+    }
+    
+    NSMutableString * exifstr = [[NSMutableString alloc] initWithCapacity: [ifdblock count] * 24];
+    NSMutableString * dbstr = [[NSMutableString alloc] initWithCapacity: 100];
+    
+    int addr=0; // current offset/address in datablock
+    if (ifd0flag) {
+        // calculate offset to datablock based on ifd file entry count
+        addr = 14+(12*([ifddatablock count]+1)); // +1 for tag 0x8769, exifsubifd offset
+    } else {
+        // same calculation as above, but no exifsubifd offset
+        addr = 14+12*[ifddatablock count];
+    }
+    
+    for (int i = 0; i < [ifdblock count]; i++) {
+        NSString * entry = [ifdblock objectAtIndex:i];
+        NSString * data = [ifddatablock objectAtIndex:i];
+        
+        // check if the data fits into 4 bytes
+        if( [data length] <= 8) {
+            // concatenate the entry and the (4byte) data entry into the final IFD entry and append to exif ifd string
+            [exifstr appendFormat : @"%@%@", entry, data];
+        } else {
+            [exifstr appendFormat : @"%@%08x", entry, addr];
+            [dbstr appendFormat: @"%@", data]; 
+            addr+= [data length] / 2;
+        }
+    }
+    
+    // calculate IFD0 terminal offset tags, currently ExifSubIFD
+    int entrycount = [ifdblock count];
+    if (ifd0flag) {
+        NSNumber * offset = [NSNumber numberWithInt:[exifstr length] / 2 + [dbstr length] / 2 ];
+        
+        [self appendExifOffsetTagTo: exifstr
+                        withOffset : offset];
+        entrycount++;
+    } 
+    return [[NSString alloc] initWithFormat: @"%04x%@%@%@",
+            entrycount,
+            exifstr,
+            @"00000000", // offset to next IFD, 0 since there is none
+            dbstr]; // lastly, the datablock
+}
+
+// Creates an exif formatted exif information file directory entry
+- (NSString*) createIFDElement: (NSString*) elementName withFormatDict : (NSDictionary*) formatdict withElementData : (NSString*) data  {
+    NSArray * fielddata = [formatdict objectForKey: elementName];// format data of desired field
+    if (fielddata) {
+        // format string @"%@%@%@%@", tag number, data format, components, value
+        NSNumber * dataformat = [fielddata objectAtIndex:1];
+        NSNumber * components = [fielddata objectAtIndex:2];
+        if([components intValue] == 0) {
+            components = [NSNumber numberWithInt: [data length] * DataTypeToWidth[[dataformat intValue]-1]];            
+        }
+
+        return [[NSString alloc] initWithFormat: @"%@%@%08x",
+                                                [fielddata objectAtIndex:0], // the field code
+                                                [self formatNumberWithLeadingZeroes: dataformat withPlaces: @4], // the data type code
+                                                [components intValue]]; // number of components
+    }
+    return NULL;
+}
+
+/**
+ * appends exif IFD0 tag 8769 "ExifOffset" to the string provided
+ * (NSMutableString*) str - string you wish to append the 8769 tag to: APP1 or IFD0 hex data string 
+ *  //  TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",
+ */
+- (void) appendExifOffsetTagTo: (NSMutableString*) str withOffset : (NSNumber*) offset {
+    NSArray * format = TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1);
+    
+    NSString * entry = [self  createIFDElement: @"ExifOffset"
+                                withFormatDict: IFD0TagFormatDict
+                               withElementData: [offset stringValue]];
+    
+    NSString * data = [self createIFDElementDataWithFormat: format
+                                                  withData: [offset stringValue]];
+    [str appendFormat:@"%@%@", entry, data];
+}
+
+// formats the Information File Directory Data to exif format
+- (NSString*) createIFDElementDataWithFormat: (NSArray*) dataformat withData: (NSString*) data {
+    NSMutableString * datastr = nil;
+    NSNumber * tmp = nil;
+    NSNumber * formatcode = [dataformat objectAtIndex:1];
+    NSNumber * num = @0;
+    NSNumber * denom = @0;
+    
+    switch ([formatcode intValue]) {
+        case EDT_UBYTE:
+            break;
+        case EDT_ASCII_STRING:
+            datastr = [[NSMutableString alloc] init];
+            for (int i = 0; i < [data length]; i++) {
+                [datastr appendFormat:@"%02x",[data characterAtIndex:i]];
+            }
+            if ([datastr length] < 8) {
+                NSString * format = [NSString stringWithFormat:@"%%0%dd", 8 - [datastr length]];
+                [datastr appendFormat:format,0];
+            }
+            return datastr;
+        case EDT_USHORT:
+            return [[NSString alloc] initWithFormat : @"%@%@",
+                    [self formattedHexStringFromDecimalNumber: [NSNumber numberWithInt: [data intValue]] withPlaces: @4],
+                    @"00000000"];
+        case EDT_ULONG:
+            tmp = [NSNumber numberWithUnsignedLong:[data intValue]];
+            return [NSString stringWithFormat : @"%@",
+                    [self formattedHexStringFromDecimalNumber: tmp withPlaces: @8]];
+        case EDT_URATIONAL:
+            return [self decimalToUnsignedRational: [NSNumber numberWithDouble:[data doubleValue]]
+                               withResultNumerator: &num
+                             withResultDenominator: &denom];
+        case EDT_SBYTE:
+            
+            break;
+        case EDT_UNDEFINED:
+            break;     // 8 bits
+        case EDT_SSHORT:
+            
+            break;
+        case EDT_SLONG:
+            break;          // 32bit signed integer (2's complement)
+        case EDT_SRATIONAL:
+            break;     // 2 SLONGS, first long is numerator, second is denominator
+        case EDT_SINGLEFLOAT:
+            break;
+        case EDT_DOUBLEFLOAT:
+            break;
+    }
+    return datastr;
+}
+
+//======================================================================================================================
+// Utility Methods
+//======================================================================================================================
+
+// creates a formatted little endian hex string from a number and width specifier
+- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb withPlaces: (NSNumber*) width {
+    NSMutableString * str = [[NSMutableString alloc] initWithCapacity:[width intValue]];
+    NSString * formatstr = [[NSString alloc] initWithFormat: @"%%%@%dx", @"0", [width intValue]];
+    [str appendFormat:formatstr, [numb intValue]];
+    return str;
+}
+
+// format number as string with leading 0's
+- (NSString*) formatNumberWithLeadingZeroes: (NSNumber *) numb withPlaces: (NSNumber *) places { 
+    NSNumberFormatter * formatter = [[NSNumberFormatter alloc] init];
+    NSString *formatstr = [@"" stringByPaddingToLength:[places unsignedIntegerValue] withString:@"0" startingAtIndex:0];
+    [formatter setPositiveFormat:formatstr];
+    return [formatter stringFromNumber:numb];
+}
+
+// approximate a decimal with a rational by method of continued fraction
+// can be collasped into decimalToUnsignedRational after testing
+- (void) decimalToRational: (NSNumber *) numb
+       withResultNumerator: (NSNumber**) numerator
+     withResultDenominator: (NSNumber**) denominator {
+    NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8];
+    
+    [self continuedFraction: [numb doubleValue]
+           withFractionList: fractionlist
+                withHorizon: 8];
+    
+    // simplify complex fraction represented by partial fraction list
+    [self expandContinuedFraction: fractionlist
+              withResultNumerator: numerator
+            withResultDenominator: denominator];
+
+}
+
+// approximate a decimal with an unsigned rational by method of continued fraction
+- (NSString*) decimalToUnsignedRational: (NSNumber *) numb
+                          withResultNumerator: (NSNumber**) numerator
+                        withResultDenominator: (NSNumber**) denominator {
+    NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8];
+    
+    // generate partial fraction list
+    [self continuedFraction: [numb doubleValue]
+           withFractionList: fractionlist
+                withHorizon: 8];
+    
+    // simplify complex fraction represented by partial fraction list
+    [self expandContinuedFraction: fractionlist
+              withResultNumerator: numerator
+            withResultDenominator: denominator];
+    
+    return [self formatFractionList: fractionlist];
+}
+
+// recursive implementation of decimal approximation by continued fraction
+- (void) continuedFraction: (double) val
+          withFractionList: (NSMutableArray*) fractionlist
+               withHorizon: (int) horizon {
+    int whole;
+    double remainder;
+    // 1. split term
+    [self splitDouble: val withIntComponent: &whole withFloatRemainder: &remainder];
+    [fractionlist addObject: [NSNumber numberWithInt:whole]];
+    
+    // 2. calculate reciprocal of remainder
+    if (!remainder) return; // early exit, exact fraction found, avoids recip/0
+    double recip = 1 / remainder;
+
+    // 3. exit condition
+    if ([fractionlist count] > horizon) {
+        return;
+    }
+    
+    // 4. recurse
+    [self continuedFraction:recip withFractionList: fractionlist withHorizon: horizon];
+    
+}
+
+// expand continued fraction list, creating a single level rational approximation
+-(void) expandContinuedFraction: (NSArray*) fractionlist
+                  withResultNumerator: (NSNumber**) numerator
+                withResultDenominator: (NSNumber**) denominator {
+    int i = 0;
+    int den = 0;
+    int num = 0;
+    if ([fractionlist count] == 1) {
+        *numerator = [NSNumber numberWithInt:[[fractionlist objectAtIndex:0] intValue]];
+        *denominator = @1;
+        return;
+    }
+    
+    //begin at the end of the list
+    i = [fractionlist count] - 1;
+    num = 1;
+    den = [[fractionlist objectAtIndex:i] intValue];
+    
+    while (i > 0) {
+        int t = [[fractionlist objectAtIndex: i-1] intValue];
+        num = t * den + num;
+        if (i==1) {
+            break;
+        } else {
+            t = num;
+            num = den;
+            den = t;
+        }
+        i--;
+    }
+    // set result parameters values
+    *numerator = [NSNumber numberWithInt: num];
+    *denominator = [NSNumber numberWithInt: den];
+}
+
+// formats expanded fraction list to string matching exif specification
+- (NSString*) formatFractionList: (NSArray *) fractionlist {
+    NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16];
+    
+    if ([fractionlist count] == 1){
+        [str appendFormat: @"%08x00000001", [[fractionlist objectAtIndex:0] intValue]];
+    }
+    return str;
+}
+
+// format rational as
+- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator withDenominator: (NSNumber*) denominator asSigned: (Boolean) signedFlag {
+    NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16];
+    if (signedFlag) {
+        long num = [numerator longValue];
+        long den = [denominator longValue];
+        [str appendFormat: @"%08lx%08lx", num >= 0 ? num : ~ABS(num) + 1, num >= 0 ? den : ~ABS(den) + 1];
+    } else {
+        [str appendFormat: @"%08lx%08lx", [numerator unsignedLongValue], [denominator unsignedLongValue]];
+    }
+    return str;
+}
+
+// split a floating point number into two integer values representing the left and right side of the decimal
+- (void) splitDouble: (double) val withIntComponent: (int*) rightside withFloatRemainder: (double*) leftside {
+    *rightside = val; // convert numb to int representation, which truncates the decimal portion
+    *leftside = val - *rightside;
+}
+
+
+//
+- (NSString*) hexStringFromData : (NSData*) data {
+    //overflow detection
+    const unsigned char *dataBuffer = [data bytes];
+    return [[NSString alloc] initWithFormat: @"%02x%02x",
+            (unsigned char)dataBuffer[0],
+            (unsigned char)dataBuffer[1]];
+}
+
+// convert a hex string to a number
+- (NSNumber*) numericFromHexString : (NSString *) hexstring {
+    NSScanner * scan = NULL;
+    unsigned int numbuf= 0;
+    
+    scan = [NSScanner scannerWithString:hexstring];
+    [scan scanHexInt:&numbuf];
+    return [NSNumber numberWithInt:numbuf];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
index cc6613f..dec6ab3 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
@@ -34,8 +34,8 @@
 + (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType;
 // Visible for testing.
 + (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict
-    bundlePath                                          :(NSString*)bundlePath
-   fileManager                                         :(NSFileManager*)fileManager;
+                                             bundlePath:(NSString*)bundlePath
+                                            fileManager:(NSFileManager*)fileManager;
 @end
 
 @interface CDVBackupInfo : NSObject

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
index 68175f1..238d680 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
@@ -35,7 +35,7 @@
 {
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive)
                                                  name:UIApplicationWillResignActiveNotification object:nil];
-    BOOL cloudBackup = [@"cloud" isEqualToString:self.commandDelegate.settings[@"BackupWebStorage"]];
+    BOOL cloudBackup = [@"cloud" isEqualToString : self.commandDelegate.settings[@"BackupWebStorage"]];
 
     self.backupInfo = [[self class] createBackupInfoWithCloudBackup:cloudBackup];
 }
@@ -64,8 +64,8 @@
     // ////////// LOCALSTORAGE
 
     original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0.localstorage":@"file__0.localstorage"];
-    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage":@"")];
-    backup = [backup stringByAppendingPathComponent:(rename ? @"localstorage.appdata.db":@"file__0.localstorage")];
+    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+    backup = [backup stringByAppendingPathComponent:(rename ? @"localstorage.appdata.db" : @"file__0.localstorage")];
 
     backupItem = [[CDVBackupInfo alloc] init];
     backupItem.backup = backup;
@@ -77,8 +77,8 @@
     // ////////// WEBSQL MAIN DB
 
     original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/Databases.db":@"Databases.db"];
-    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage":@"")];
-    backup = [backup stringByAppendingPathComponent:(rename ? @"websqlmain.appdata.db":@"Databases.db")];
+    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+    backup = [backup stringByAppendingPathComponent:(rename ? @"websqlmain.appdata.db" : @"Databases.db")];
 
     backupItem = [[CDVBackupInfo alloc] init];
     backupItem.backup = backup;
@@ -90,8 +90,8 @@
     // ////////// WEBSQL DATABASES
 
     original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0":@"file__0"];
-    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage":@"")];
-    backup = [backup stringByAppendingPathComponent:(rename ? @"websqldbs.appdata.db":@"file__0")];
+    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+    backup = [backup stringByAppendingPathComponent:(rename ? @"websqldbs.appdata.db" : @"file__0")];
 
     backupItem = [[CDVBackupInfo alloc] init];
     backupItem.backup = backup;
@@ -106,8 +106,8 @@
 + (NSMutableArray*)createBackupInfoWithCloudBackup:(BOOL)cloudBackup
 {
     // create backup info from backup folder to caches folder
-    NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains (NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
-    NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
     NSString* cacheFolder = [appLibraryFolder stringByAppendingPathComponent:@"Caches"];
     NSString* backupsFolder = [appDocumentsFolder stringByAppendingPathComponent:@"Backups"];
 
@@ -131,7 +131,7 @@
     return success;
 }
 
-+ (BOOL)copyFrom:(NSString*)src to:(NSString*)dest error:(NSError * __autoreleasing*)error
++ (BOOL)copyFrom:(NSString*)src to:(NSString*)dest error:(NSError* __autoreleasing*)error
 {
     NSFileManager* fileManager = [NSFileManager defaultManager];
 
@@ -149,7 +149,7 @@
     // generate unique filepath in temp directory
     CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
     CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
-    NSString* tempBackup = [[NSTemporaryDirectory () stringByAppendingPathComponent:(__bridge NSString*)uuidString] stringByAppendingPathExtension:@"bak"];
+    NSString* tempBackup = [[NSTemporaryDirectory() stringByAppendingPathComponent:(__bridge NSString*)uuidString] stringByAppendingPathExtension:@"bak"];
     CFRelease(uuidString);
     CFRelease(uuidRef);
 
@@ -334,8 +334,8 @@
         return;
     }
 
-    NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains (NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
-    NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
 
     NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:0];
 
@@ -386,15 +386,15 @@
         backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
                 [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
                 backgroundTaskID = UIBackgroundTaskInvalid;
-                NSLog (@"Background task to backup WebSQL/LocalStorage expired.");
+                NSLog(@"Background task to backup WebSQL/LocalStorage expired.");
             }];
         CDVLocalStorage __weak* weakSelf = self;
         [self.commandDelegate runInBackground:^{
-                [weakSelf backup:nil];
+            [weakSelf backup:nil];
 
-                [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
-                backgroundTaskID = UIBackgroundTaskInvalid;
-            }];
+            [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
+            backgroundTaskID = UIBackgroundTaskInvalid;
+        }];
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
index 7087d43..caf0798 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
@@ -83,11 +83,11 @@ typedef NSUInteger CDVLocationStatus;
 - (void)startLocation:(BOOL)enableHighAccuracy;
 
 - (void)locationManager:(CLLocationManager*)manager
-   didUpdateToLocation :(CLLocation*)newLocation
-          fromLocation        :(CLLocation*)oldLocation;
+    didUpdateToLocation:(CLLocation*)newLocation
+           fromLocation:(CLLocation*)oldLocation;
 
 - (void)locationManager:(CLLocationManager*)manager
-   didFailWithError    :(NSError*)error;
+       didFailWithError:(NSError*)error;
 
 - (BOOL)isLocationServicesEnabled;
 
@@ -97,7 +97,7 @@ typedef NSUInteger CDVLocationStatus;
 - (void)stopHeading:(CDVInvokedUrlCommand*)command;
 - (void)startHeadingWithFilter:(CLLocationDegrees)filter;
 - (void)locationManager:(CLLocationManager*)manager
-   didUpdateHeading    :(CLHeading*)heading;
+       didUpdateHeading:(CLHeading*)heading;
 
 - (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
index 07af30e..ed9ec26 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
@@ -591,17 +591,17 @@
 - (NSString*)JSONRepresentation
 {
     return [NSString stringWithFormat:
-        @"{ timestamp: %.00f, \
+           @"{ timestamp: %.00f, \
             coords: { latitude: %f, longitude: %f, altitude: %.02f, heading: %.02f, speed: %.02f, accuracy: %.02f, altitudeAccuracy: %.02f } \
             }",
-        [self.timestamp timeIntervalSince1970] * 1000.0,
-        self.coordinate.latitude,
-        self.coordinate.longitude,
-        self.altitude,
-        self.course,
-        self.speed,
-        self.horizontalAccuracy,
-        self.verticalAccuracy
+           [self.timestamp timeIntervalSince1970] * 1000.0,
+           self.coordinate.latitude,
+           self.coordinate.longitude,
+           self.altitude,
+           self.course,
+           self.speed,
+           self.horizontalAccuracy,
+           self.verticalAccuracy
     ];
 }
 
@@ -614,9 +614,9 @@
 - (NSString*)JSONRepresentation
 {
     return [NSString stringWithFormat:
-        @"{ code: %d, message: '%@'}",
-        self.code,
-        [self localizedDescription]
+           @"{ code: %d, message: '%@'}",
+           self.code,
+           [self localizedDescription]
     ];
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
index 1eedb54..5b5b89f 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
@@ -26,6 +26,7 @@
 
 - (void)alert:(CDVInvokedUrlCommand*)command;
 - (void)confirm:(CDVInvokedUrlCommand*)command;
+- (void)prompt:(CDVInvokedUrlCommand*)command;
 - (void)vibrate:(CDVInvokedUrlCommand*)command;
 
 @end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
index 992239e..821cb9f 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
@@ -20,12 +20,24 @@
 #import "CDVNotification.h"
 #import "NSDictionary+Extensions.h"
 
+#define DIALOG_TYPE_ALERT @"alert"
+#define DIALOG_TYPE_PROMPT @"prompt"
+
 @implementation CDVNotification
 
-- (void)showDialogWithMessage:(NSString*)message title:(NSString*)title buttons:(NSString*)buttons callbackId:(NSString*)callbackId
+/*
+ * showDialogWithMessage - Common method to instantiate the alert view for alert, confirm, and prompt notifications.
+ * Parameters:
+ *  message       The alert view message.
+ *  title         The alert view title.
+ *  buttons       The array of customized strings for the buttons.
+ *  callbackId    The commmand callback id.
+ *  dialogType    The type of alert view [alert | prompt].
+ */
+- (void)showDialogWithMessage:(NSString*)message title:(NSString*)title buttons:(NSArray*)buttons callbackId:(NSString*)callbackId dialogType:(NSString*)dialogType
 {
     CDVAlertView* alertView = [[CDVAlertView alloc]
-            initWithTitle:title
+        initWithTitle:title
                   message:message
                  delegate:self
         cancelButtonTitle:nil
@@ -33,11 +45,14 @@
 
     alertView.callbackId = callbackId;
 
-    NSArray* labels = [buttons componentsSeparatedByString:@","];
-    int count = [labels count];
+    int count = [buttons count];
 
     for (int n = 0; n < count; n++) {
-        [alertView addButtonWithTitle:[labels objectAtIndex:n]];
+        [alertView addButtonWithTitle:[buttons objectAtIndex:n]];
+    }
+
+    if ([dialogType isEqualToString:DIALOG_TYPE_PROMPT]) {
+        alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
     }
 
     [alertView show];
@@ -46,52 +61,54 @@
 - (void)alert:(CDVInvokedUrlCommand*)command
 {
     NSString* callbackId = command.callbackId;
-    NSArray* arguments = command.arguments;
-    int argc = [arguments count];
-
-    NSString* message = argc > 0 ? [arguments objectAtIndex:0] : nil;
-    NSString* title = argc > 1 ? [arguments objectAtIndex:1] : nil;
-    NSString* buttons = argc > 2 ? [arguments objectAtIndex:2] : nil;
-
-    if (!title) {
-        title = NSLocalizedString(@"Alert", @"Alert");
-    }
-    if (!buttons) {
-        buttons = NSLocalizedString(@"OK", @"OK");
-    }
+    NSString* message = [command argumentAtIndex:0];
+    NSString* title = [command argumentAtIndex:1];
+    NSString* buttons = [command argumentAtIndex:2];
 
-    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId];
+    [self showDialogWithMessage:message title:title buttons:@[buttons] callbackId:callbackId dialogType:DIALOG_TYPE_ALERT];
 }
 
 - (void)confirm:(CDVInvokedUrlCommand*)command
 {
     NSString* callbackId = command.callbackId;
-    NSArray* arguments = command.arguments;
-    int argc = [arguments count];
+    NSString* message = [command argumentAtIndex:0];
+    NSString* title = [command argumentAtIndex:1];
+    NSArray* buttons = [command argumentAtIndex:2];
 
-    NSString* message = argc > 0 ? [arguments objectAtIndex:0] : nil;
-    NSString* title = argc > 1 ? [arguments objectAtIndex:1] : nil;
-    NSString* buttons = argc > 2 ? [arguments objectAtIndex:2] : nil;
+    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId dialogType:DIALOG_TYPE_ALERT];
+}
 
-    if (!title) {
-        title = NSLocalizedString(@"Confirm", @"Confirm");
-    }
-    if (!buttons) {
-        buttons = NSLocalizedString(@"OK,Cancel", @"OK,Cancel");
-    }
+- (void)prompt:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+    NSString* message = [command argumentAtIndex:0];
+    NSString* title = [command argumentAtIndex:1];
+    NSArray* buttons = [command argumentAtIndex:2];
 
-    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId];
+    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId dialogType:DIALOG_TYPE_PROMPT];
 }
 
 /**
- Callback invoked when an alert dialog's buttons are clicked.
- Passes the index + label back to JS
- */
+  * Callback invoked when an alert dialog's buttons are clicked.
+  */
 - (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
 {
     CDVAlertView* cdvAlertView = (CDVAlertView*)alertView;
-    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:++buttonIndex];
-
+    CDVPluginResult* result;
+
+    // Determine what gets returned to JS based on the alert view type.
+    if (alertView.alertViewStyle == UIAlertViewStyleDefault) {
+        // For alert and confirm, return button index as int back to JS.
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:buttonIndex + 1];
+    } else {
+        // For prompt, return button index and input text back to JS.
+        NSString* value0 = [[alertView textFieldAtIndex:0] text];
+        NSDictionary* info = @{
+            @"buttonIndex":@(buttonIndex + 1),
+            @"input1":(value0 ? value0 : [NSNull null])
+        };
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:info];
+    }
     [self.commandDelegate sendPluginResult:result callbackId:cdvAlertView.callbackId];
 }