aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xiPhone/CordovaLib/Classes/CDV.h3
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVAvailability.h4
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVCamera.h4
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVCamera.m159
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVCapture.m5
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVCommandDelegate.h7
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVCommandDelegateImpl.m24
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVCommandQueue.m4
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVConfigParser.h5
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVConfigParser.m23
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVContact.m49
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVDevice.m3
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVEcho.m14
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVFile.h2
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVFile.m341
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVFileTransfer.h5
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVFileTransfer.m173
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVInAppBrowser.h21
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVInAppBrowser.m162
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVInvokedUrlCommand.m30
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVJSON.h (renamed from iPhone/CordovaLib/Classes/CDVCordovaView.h)11
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVJSON.m77
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVLocalStorage.h2
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVLocalStorage.m48
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVLocation.m14
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVPlugin.h4
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVPlugin.m51
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVPluginResult.h2
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVPluginResult.m40
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVSound.h8
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVSound.m156
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVSplashScreen.h6
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVSplashScreen.m151
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVURLProtocol.h3
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVURLProtocol.m83
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVUserAgentUtil.h (renamed from iPhone/CordovaLib/Classes/CDVCordovaView.m)22
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVUserAgentUtil.m120
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVViewController.h18
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVViewController.m341
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVWebViewDelegate.h37
-rwxr-xr-xiPhone/CordovaLib/Classes/CDVWebViewDelegate.m157
-rwxr-xr-xiPhone/CordovaLib/Classes/JSON/JSONKit.h251
-rwxr-xr-xiPhone/CordovaLib/Classes/JSON/JSONKit.m3061
-rwxr-xr-xiPhone/CordovaLib/CordovaLib.xcodeproj/project.pbxproj63
-rw-r--r--iPhone/CordovaLib/CordovaLib.xcodeproj/xcuserdata/struan.xcuserdatad/xcschemes/xcschememanagement.plist2
-rwxr-xr-xiPhone/CordovaLib/VERSION2
-rw-r--r--iPhone/FixMyStreet.xcodeproj/project.pbxproj18
-rw-r--r--iPhone/FixMyStreet/Classes/AppDelegate.m10
-rw-r--r--iPhone/FixMyStreet/config.xml7
-rwxr-xr-xiPhone/cordova/build51
-rwxr-xr-xiPhone/cordova/emulate55
-rwxr-xr-xiPhone/cordova/log23
-rwxr-xr-xiPhone/cordova/release51
-rwxr-xr-xiPhone/cordova/run58
-rw-r--r--www/cordova-independent.js2
-rwxr-xr-xwww/cordova-ios-2.5.0.js6083
56 files changed, 8062 insertions, 4064 deletions
diff --git a/iPhone/CordovaLib/Classes/CDV.h b/iPhone/CordovaLib/Classes/CDV.h
index 5367799..5a0ae6a 100755
--- a/iPhone/CordovaLib/Classes/CDV.h
+++ b/iPhone/CordovaLib/Classes/CDV.h
@@ -32,7 +32,6 @@
#import "CDVConnection.h"
#import "CDVContact.h"
#import "CDVContacts.h"
-#import "CDVCordovaView.h"
#import "CDVDebug.h"
#import "CDVDebugConsole.h"
#import "CDVDevice.h"
@@ -55,4 +54,4 @@
#import "NSMutableArray+QueueAdditions.h"
#import "UIDevice+Extensions.h"
-#import "JSONKit.h"
+#import "CDVJSON.h"
diff --git a/iPhone/CordovaLib/Classes/CDVAvailability.h b/iPhone/CordovaLib/Classes/CDVAvailability.h
index d2e7f1b..33c6799 100755
--- a/iPhone/CordovaLib/Classes/CDVAvailability.h
+++ b/iPhone/CordovaLib/Classes/CDVAvailability.h
@@ -35,6 +35,8 @@
#define __CORDOVA_2_1_0 20100
#define __CORDOVA_2_2_0 20200
#define __CORDOVA_2_3_0 20300
+#define __CORDOVA_2_4_0 20400
+#define __CORDOVA_2_5_0 20500
#define __CORDOVA_NA 99999 /* not available */
/*
@@ -45,7 +47,7 @@
#endif
*/
#ifndef CORDOVA_VERSION_MIN_REQUIRED
- #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_3_0
+ #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_5_0
#endif
/*
diff --git a/iPhone/CordovaLib/Classes/CDVCamera.h b/iPhone/CordovaLib/Classes/CDVCamera.h
index 2905a8a..204d25f 100755
--- a/iPhone/CordovaLib/Classes/CDVCamera.h
+++ b/iPhone/CordovaLib/Classes/CDVCamera.h
@@ -22,7 +22,8 @@
enum CDVDestinationType {
DestinationTypeDataUrl = 0,
- DestinationTypeFileUri
+ DestinationTypeFileUri,
+ DestinationTypeNativeUri
};
typedef NSUInteger CDVDestinationType;
@@ -79,6 +80,7 @@ typedef NSUInteger CDVMediaType;
- (void)takePicture:(CDVInvokedUrlCommand*)command;
- (void)postImage:(UIImage*)anImage withFilename:(NSString*)filename toUrl:(NSURL*)url;
- (void)cleanup:(CDVInvokedUrlCommand*)command;
+- (void)repositionPopover:(CDVInvokedUrlCommand*)command;
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info;
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo;
diff --git a/iPhone/CordovaLib/Classes/CDVCamera.m b/iPhone/CordovaLib/Classes/CDVCamera.m
index cfbf415..aabe844 100755
--- a/iPhone/CordovaLib/Classes/CDVCamera.m
+++ b/iPhone/CordovaLib/Classes/CDVCamera.m
@@ -93,6 +93,13 @@ static NSSet* org_apache_cordova_validArrowDirections;
targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]);
}
+ // If a popover is already open, close it; we only want one at a time.
+ if (([[self pickerController] popoverController] != nil) && [[[self pickerController] popoverController] isPopoverVisible]) {
+ [[[self pickerController] popoverController] dismissPopoverAnimated:YES];
+ [[[self pickerController] popoverController] setDelegate:nil];
+ [[self pickerController] setPopoverController:nil];
+ }
+
CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init];
self.pickerController = cameraPicker;
@@ -128,28 +135,8 @@ static NSSet* org_apache_cordova_validArrowDirections;
if (cameraPicker.popoverController == nil) {
cameraPicker.popoverController = [[NSClassFromString (@"UIPopoverController")alloc] initWithContentViewController:cameraPicker];
}
- int x = 0;
- int y = 32;
- int width = 320;
- int height = 480;
- UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirectionAny;
NSDictionary* options = [command.arguments objectAtIndex:10 withDefault:nil];
- if (options) {
- x = [options integerValueForKey:@"x" defaultValue:0];
- y = [options integerValueForKey:@"y" defaultValue:32];
- width = [options integerValueForKey:@"width" defaultValue:320];
- height = [options integerValueForKey:@"height" defaultValue:480];
- arrowDirection = [options integerValueForKey:@"arrowDir" defaultValue:UIPopoverArrowDirectionAny];
- if (![org_apache_cordova_validArrowDirections containsObject:[NSNumber numberWithInt:arrowDirection]]) {
- arrowDirection = UIPopoverArrowDirectionAny;
- }
- }
-
- cameraPicker.popoverController.delegate = self;
- [cameraPicker.popoverController presentPopoverFromRect:CGRectMake(x, y, width, height)
- inView:[self.webView superview]
- permittedArrowDirections:arrowDirection
- animated:YES];
+ [self displayPopover:options];
} else {
if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
[self.viewController presentViewController:cameraPicker animated:YES completion:nil];
@@ -160,6 +147,39 @@ static NSSet* org_apache_cordova_validArrowDirections;
self.hasPendingOperation = YES;
}
+- (void)repositionPopover:(CDVInvokedUrlCommand*)command
+{
+ NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:nil];
+
+ [self displayPopover:options];
+}
+
+- (void)displayPopover:(NSDictionary*)options
+{
+ int x = 0;
+ int y = 32;
+ int width = 320;
+ int height = 480;
+ UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirectionAny;
+
+ if (options) {
+ x = [options integerValueForKey:@"x" defaultValue:0];
+ y = [options integerValueForKey:@"y" defaultValue:32];
+ width = [options integerValueForKey:@"width" defaultValue:320];
+ height = [options integerValueForKey:@"height" defaultValue:480];
+ arrowDirection = [options integerValueForKey:@"arrowDir" defaultValue:UIPopoverArrowDirectionAny];
+ if (![org_apache_cordova_validArrowDirections containsObject:[NSNumber numberWithInt:arrowDirection]]) {
+ arrowDirection = UIPopoverArrowDirectionAny;
+ }
+ }
+
+ [[[self pickerController] popoverController] setDelegate:self];
+ [[[self pickerController] popoverController] presentPopoverFromRect:CGRectMake(x, y, width, height)
+ inView:[self.webView superview]
+ permittedArrowDirections:arrowDirection
+ animated:YES];
+}
+
- (void)cleanup:(CDVInvokedUrlCommand*)command
{
// empty the tmp directory
@@ -232,63 +252,68 @@ static NSSet* org_apache_cordova_validArrowDirections;
NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
// IMAGE TYPE
if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
- // get the image
- UIImage* image = nil;
- if (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) {
- image = [info objectForKey:UIImagePickerControllerEditedImage];
+ if (cameraPicker.returnType == DestinationTypeNativeUri) {
+ NSString* nativeUri = [(NSURL*)[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri];
} else {
- image = [info objectForKey:UIImagePickerControllerOriginalImage];
- }
+ // get the image
+ UIImage* image = nil;
+ if (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) {
+ image = [info objectForKey:UIImagePickerControllerEditedImage];
+ } else {
+ image = [info objectForKey:UIImagePickerControllerOriginalImage];
+ }
- if (cameraPicker.saveToPhotoAlbum) {
- UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
- }
+ if (cameraPicker.saveToPhotoAlbum) {
+ UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
+ }
- if (cameraPicker.correctOrientation) {
- image = [self imageCorrectedForCaptureOrientation:image];
- }
+ if (cameraPicker.correctOrientation) {
+ image = [self imageCorrectedForCaptureOrientation:image];
+ }
- UIImage* scaledImage = nil;
+ UIImage* scaledImage = nil;
- if ((cameraPicker.targetSize.width > 0) && (cameraPicker.targetSize.height > 0)) {
- // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
- if (cameraPicker.cropToSize) {
- scaledImage = [self imageByScalingAndCroppingForSize:image toSize:cameraPicker.targetSize];
- } else {
- scaledImage = [self imageByScalingNotCroppingForSize:image toSize:cameraPicker.targetSize];
+ if ((cameraPicker.targetSize.width > 0) && (cameraPicker.targetSize.height > 0)) {
+ // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
+ if (cameraPicker.cropToSize) {
+ scaledImage = [self imageByScalingAndCroppingForSize:image toSize:cameraPicker.targetSize];
+ } else {
+ scaledImage = [self imageByScalingNotCroppingForSize:image toSize:cameraPicker.targetSize];
+ }
}
- }
- NSData* data = nil;
+ NSData* data = nil;
- if (cameraPicker.encodingType == EncodingTypePNG) {
- data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage);
- } else {
- data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f);
- }
+ if (cameraPicker.encodingType == EncodingTypePNG) {
+ data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage);
+ } else {
+ data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f);
+ }
- if (cameraPicker.returnType == DestinationTypeFileUri) {
- // write to temp directory and return URI
- // get the temp directory path
- NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];
- NSError* err = nil;
- NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by apple (vs [NSFileManager defaultManager]) to be threadsafe
- // generate unique file name
- NSString* filePath;
-
- int i = 1;
- do {
- filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, cameraPicker.encodingType == EncodingTypePNG ? @"png":@"jpg"];
- } while ([fileMgr fileExistsAtPath:filePath]);
-
- // save file
- if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
+ if (cameraPicker.returnType == DestinationTypeFileUri) {
+ // write to temp directory and return URI
+ // get the temp directory path
+ NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];
+ NSError* err = nil;
+ NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by apple (vs [NSFileManager defaultManager]) to be threadsafe
+ // generate unique file name
+ NSString* filePath;
+
+ int i = 1;
+ do {
+ filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, cameraPicker.encodingType == EncodingTypePNG ? @"png":@"jpg"];
+ } while ([fileMgr fileExistsAtPath:filePath]);
+
+ // save file
+ if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
+ } else {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]];
+ }
} else {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[data base64EncodedString]];
}
- } else {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[data base64EncodedString]];
}
}
// NOT IMAGE TYPE (MOVIE)
diff --git a/iPhone/CordovaLib/Classes/CDVCapture.m b/iPhone/CordovaLib/Classes/CDVCapture.m
index 6d52042..ed9f664 100755
--- a/iPhone/CordovaLib/Classes/CDVCapture.m
+++ b/iPhone/CordovaLib/Classes/CDVCapture.m
@@ -18,9 +18,8 @@
*/
#import "CDVCapture.h"
-#import "JSONKit.h"
+#import "CDVJSON.h"
#import "CDVAvailability.h"
-#import "CDVViewController.h"
#define kW3CMediaFormatHeight @"height"
#define kW3CMediaFormatWidth @"width"
@@ -329,7 +328,7 @@
movieArray ? (NSObject*) movieArray:[NSNull null], @"video",
audioArray ? (NSObject*) audioArray:[NSNull null], @"audio",
nil];
- NSString* jsString = [NSString stringWithFormat:@"navigator.device.capture.setSupportedModes(%@);", [modes cdvjk_JSONString]];
+ NSString* jsString = [NSString stringWithFormat:@"navigator.device.capture.setSupportedModes(%@);", [modes JSONString]];
[self.commandDelegate evalJs:jsString];
}
diff --git a/iPhone/CordovaLib/Classes/CDVCommandDelegate.h b/iPhone/CordovaLib/Classes/CDVCommandDelegate.h
index 4a53f98..e177c63 100755
--- a/iPhone/CordovaLib/Classes/CDVCommandDelegate.h
+++ b/iPhone/CordovaLib/Classes/CDVCommandDelegate.h
@@ -22,9 +22,12 @@
@class CDVPlugin;
@class CDVPluginResult;
+@class CDVWhitelist;
@protocol CDVCommandDelegate <NSObject>
+@property (nonatomic, readonly) NSDictionary* settings;
+
- (NSString*)pathForResource:(NSString*)resourcepath;
- (id)getCommandInstance:(NSString*)pluginName;
- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className CDV_DEPRECATED(2.2, "Use CDVViewController to register plugins, or use config.xml.");
@@ -44,5 +47,9 @@
- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop;
// Runs the given block on a background thread using a shared thread-pool.
- (void)runInBackground:(void (^)())block;
+// Returns the User-Agent of the associated UIWebView.
+- (NSString*)userAgent;
+// Returns whether the given URL passes the white-list.
+- (BOOL)URLIsWhitelisted:(NSURL*)url;
@end
diff --git a/iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.m b/iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.m
index 76413bd..e399289 100755
--- a/iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.m
+++ b/iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.m
@@ -18,7 +18,7 @@
*/
#import "CDVCommandDelegateImpl.h"
-
+#import "CDVJSON.h"
#import "CDVCommandQueue.h"
#import "CDVPluginResult.h"
#import "CDVViewController.h"
@@ -78,13 +78,17 @@
- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId
{
+ // This occurs when there is are no win/fail callbacks for the call.
+ if ([@"INVALID" isEqualToString:callbackId]) {
+ return;
+ }
int status = [result.status intValue];
BOOL keepCallback = [result.keepCallback boolValue];
id message = result.message == nil ? [NSNull null] : result.message;
// Use an array to encode the message as JSON.
message = [NSArray arrayWithObject:message];
- NSString* encodedMessage = [message cdvjk_JSONString];
+ NSString* encodedMessage = [message JSONString];
// And then strip off the outer []s.
encodedMessage = [encodedMessage substringWithRange:NSMakeRange(1, [encodedMessage length] - 2)];
NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d)",
@@ -128,4 +132,20 @@
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
}
+- (NSString*)userAgent
+{
+ return [_viewController userAgent];
+}
+
+- (BOOL)URLIsWhitelisted:(NSURL*)url
+{
+ return ![_viewController.whitelist schemeIsAllowed:[url scheme]] ||
+ [_viewController.whitelist URLIsAllowed:url];
+}
+
+- (NSDictionary*)settings
+{
+ return _viewController.settings;
+}
+
@end
diff --git a/iPhone/CordovaLib/Classes/CDVCommandQueue.m b/iPhone/CordovaLib/Classes/CDVCommandQueue.m
index d88a730..a8a58b7 100755
--- a/iPhone/CordovaLib/Classes/CDVCommandQueue.m
+++ b/iPhone/CordovaLib/Classes/CDVCommandQueue.m
@@ -87,14 +87,14 @@
for (NSUInteger i = 0; i < [_queue count]; ++i) {
// Parse the returned JSON array.
- NSArray* commandBatch = [[_queue objectAtIndex:i] cdvjk_mutableObjectFromJSONString];
+ NSArray* commandBatch = [[_queue objectAtIndex:i] JSONObject];
// Iterate over and execute all of the commands.
for (NSArray* jsonEntry in commandBatch) {
CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry];
if (![self execute:command]) {
#ifdef DEBUG
- NSString* commandJson = [jsonEntry cdvjk_JSONString];
+ NSString* commandJson = [jsonEntry JSONString];
static NSUInteger maxLogLength = 1024;
NSString* commandString = ([commandJson length] > maxLogLength) ?
[NSString stringWithFormat:@"%@[...]", [commandJson substringToIndex:maxLogLength]] :
diff --git a/iPhone/CordovaLib/Classes/CDVConfigParser.h b/iPhone/CordovaLib/Classes/CDVConfigParser.h
index 23cdd01..7392580 100755
--- a/iPhone/CordovaLib/Classes/CDVConfigParser.h
+++ b/iPhone/CordovaLib/Classes/CDVConfigParser.h
@@ -17,11 +17,12 @@
under the License.
*/
-@interface CDVConfigParser : NSObject <NSXMLParserDelegate> {
-}
+@interface CDVConfigParser : NSObject <NSXMLParserDelegate>{}
@property (nonatomic, readonly, strong) NSMutableDictionary* pluginsDict;
@property (nonatomic, readonly, strong) NSMutableDictionary* settings;
@property (nonatomic, readonly, strong) NSMutableArray* whitelistHosts;
+@property (nonatomic, readonly, strong) NSMutableArray* startupPluginNames;
+@property (nonatomic, readonly, strong) NSString* startPage;
@end
diff --git a/iPhone/CordovaLib/Classes/CDVConfigParser.m b/iPhone/CordovaLib/Classes/CDVConfigParser.m
index b596c9d..6fd5913 100755
--- a/iPhone/CordovaLib/Classes/CDVConfigParser.m
+++ b/iPhone/CordovaLib/Classes/CDVConfigParser.m
@@ -24,20 +24,23 @@
@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginsDict;
@property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
@property (nonatomic, readwrite, strong) NSMutableArray* whitelistHosts;
+@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames;
+@property (nonatomic, readwrite, strong) NSString* startPage;
@end
@implementation CDVConfigParser
-@synthesize pluginsDict, settings, whitelistHosts;
+@synthesize pluginsDict, settings, whitelistHosts, startPage, startupPluginNames;
- (id)init
{
self = [super init];
if (self != nil) {
- self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:4];
- self.settings = [[NSMutableDictionary alloc] initWithCapacity:4];
- self.whitelistHosts = [[NSMutableArray alloc] initWithCapacity:1];
+ self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:30];
+ self.settings = [[NSMutableDictionary alloc] initWithCapacity:30];
+ self.whitelistHosts = [[NSMutableArray alloc] initWithCapacity:30];
+ self.startupPluginNames = [[NSMutableArray alloc] initWithCapacity:8];
}
return self;
}
@@ -45,11 +48,17 @@
- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict
{
if ([elementName isEqualToString:@"preference"]) {
- [settings setObject:[attributeDict objectForKey:@"value"] forKey:[attributeDict objectForKey:@"name"]];
+ settings[attributeDict[@"name"]] = attributeDict[@"value"];
} else if ([elementName isEqualToString:@"plugin"]) {
- [pluginsDict setObject:[attributeDict objectForKey:@"value"] forKey:[attributeDict objectForKey:@"name"]];
+ NSString* name = [attributeDict[@"name"] lowercaseString];
+ pluginsDict[name] = attributeDict[@"value"];
+ if ([@"true" isEqualToString:attributeDict[@"onload"]]) {
+ [self.startupPluginNames addObject:name];
+ }
} else if ([elementName isEqualToString:@"access"]) {
- [whitelistHosts addObject:[attributeDict objectForKey:@"origin"]];
+ [whitelistHosts addObject:attributeDict[@"origin"]];
+ } else if ([elementName isEqualToString:@"content"]) {
+ self.startPage = attributeDict[@"src"];
}
}
diff --git a/iPhone/CordovaLib/Classes/CDVContact.m b/iPhone/CordovaLib/Classes/CDVContact.m
index 9389207..9efaf10 100755
--- a/iPhone/CordovaLib/Classes/CDVContact.m
+++ b/iPhone/CordovaLib/Classes/CDVContact.m
@@ -1146,7 +1146,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
if (fields == nil) { // no name fields requested
return nil;
}
- id __weak value;
+ CFStringRef value;
NSObject* addresses;
ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonAddressProperty);
CFIndex count = multi ? ABMultiValueGetCount(multi) : 0;
@@ -1174,7 +1174,13 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
id key = [[CDVContact defaultW3CtoAB] valueForKey:k];
if (key && ![k isKindOfClass:[NSNull class]]) {
bFound = CFDictionaryGetValueIfPresent(dict, (__bridge const void*)key, (void*)&value);
- [newAddress setObject:(bFound && value != NULL) ? (id) value:[NSNull null] forKey:k];
+ if (bFound && (value != NULL)) {
+ CFRetain(value);
+ [newAddress setObject:(__bridge id)value forKey:k];
+ CFRelease(value);
+ } else {
+ [newAddress setObject:[NSNull null] forKey:k];
+ }
} else {
// was a property that iPhone doesn't support
[newAddress setObject:[NSNull null] forKey:k];
@@ -1221,16 +1227,28 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:3];
// iOS has label property (work, home, other) for each IM but W3C contact API doesn't use
CFDictionaryRef dict = (CFDictionaryRef)ABMultiValueCopyValueAtIndex(multi, i);
- NSString* __weak value; // all values should be CFStringRefs / NSString*
+ CFStringRef value; // all values should be CFStringRefs / NSString*
bool bFound;
if ([fields containsObject:kW3ContactFieldValue]) {
// value = user name
bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageUsernameKey, (void*)&value);
- [newDict setObject:(bFound && value != NULL) ? (id) value:[NSNull null] forKey:kW3ContactFieldValue];
+ if (bFound && (value != NULL)) {
+ CFRetain(value);
+ [newDict setObject:(__bridge id)value forKey:kW3ContactFieldValue];
+ CFRelease(value);
+ } else {
+ [newDict setObject:[NSNull null] forKey:kW3ContactFieldValue];
+ }
}
if ([fields containsObject:kW3ContactFieldType]) {
bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageServiceKey, (void*)&value);
- [newDict setObject:(bFound && value != NULL) ? (id)[[CDVContact class] convertPropertyLabelToContactType:value]:[NSNull null] forKey:kW3ContactFieldType];
+ if (bFound && (value != NULL)) {
+ CFRetain(value);
+ [newDict setObject:(id)[[CDVContact class] convertPropertyLabelToContactType:(__bridge NSString*)value] forKey:kW3ContactFieldType];
+ CFRelease(value);
+ } else {
+ [newDict setObject:[NSNull null] forKey:kW3ContactFieldType];
+ }
}
// always set ID
id identifier = [NSNumber numberWithUnsignedInt:ABMultiValueGetIdentifierAtIndex(multi, i)];
@@ -1311,13 +1329,14 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
// get the temp directory path
NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];
NSError* err = nil;
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- // generate unique file name
- NSString* filePath;
- int i = 1;
- do {
- filePath = [NSString stringWithFormat:@"%@/photo_%03d.jpg", docsPath, i++];
- } while ([fileMgr fileExistsAtPath:filePath]);
+ NSString* filePath = [NSString stringWithFormat:@"%@/photo_XXXXX", docsPath];
+ char template[filePath.length + 1];
+ strcpy(template, [filePath cStringUsingEncoding:NSASCIIStringEncoding]);
+ mkstemp(template);
+ filePath = [[NSFileManager defaultManager]
+ stringWithFileSystemRepresentation:template
+ length:strlen(template)];
+
// save file
if ([data writeToFile:filePath options:NSAtomicWrite error:&err]) {
photos = [NSMutableArray arrayWithCapacity:1];
@@ -1694,7 +1713,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
for (NSString* member in fields) {
NSString* abKey = [[CDVContact defaultW3CtoAB] valueForKey:member]; // im and address fields are all strings
- NSString* __weak abValue = nil;
+ CFStringRef abValue = nil;
if (abKey) {
NSString* testString = nil;
if ([member isEqualToString:kW3ContactImType]) {
@@ -1708,8 +1727,10 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
if (testString != nil) {
BOOL bExists = CFDictionaryGetValueIfPresent(dict, (__bridge const void*)abKey, (void*)&abValue);
if (bExists) {
+ CFRetain(abValue);
NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testString];
- bFound = [containPred evaluateWithObject:abValue];
+ bFound = [containPred evaluateWithObject:(__bridge id)abValue];
+ CFRelease(abValue);
}
}
}
diff --git a/iPhone/CordovaLib/Classes/CDVDevice.m b/iPhone/CordovaLib/Classes/CDVDevice.m
index 3fa4bb3..cc7ad89 100755
--- a/iPhone/CordovaLib/Classes/CDVDevice.m
+++ b/iPhone/CordovaLib/Classes/CDVDevice.m
@@ -58,7 +58,8 @@
NSDictionary* temp = [CDVViewController getBundlePlist:@"Settings"];
if ([temp respondsToSelector:@selector(JSONString)]) {
- NSString* js = [NSString stringWithFormat:@"window.Settings = %@;", [temp cdvjk_JSONString]];
+ NSLog(@"Deprecation warning: window.Setting will be removed Aug 2013. Refer to https://issues.apache.org/jira/browse/CB-2433");
+ NSString* js = [NSString stringWithFormat:@"window.Settings = %@;", [temp JSONString]];
[self.commandDelegate evalJs:js];
}
diff --git a/iPhone/CordovaLib/Classes/CDVEcho.m b/iPhone/CordovaLib/Classes/CDVEcho.m
index 9cda957..916e315 100755
--- a/iPhone/CordovaLib/Classes/CDVEcho.m
+++ b/iPhone/CordovaLib/Classes/CDVEcho.m
@@ -24,7 +24,8 @@
- (void)echo:(CDVInvokedUrlCommand*)command
{
- CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[command.arguments objectAtIndex:0]];
+ id message = [command.arguments objectAtIndex:0];
+ CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
@@ -36,9 +37,18 @@
- (void)echoAsync:(CDVInvokedUrlCommand*)command
{
- CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[command.arguments objectAtIndex:0]];
+ id message = [command.arguments objectAtIndex:0];
+ CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message];
[self performSelector:@selector(echoAsyncHelper:) withObject:[NSArray arrayWithObjects:pluginResult, command.callbackId, nil] afterDelay:0];
}
+- (void)echoArrayBuffer:(CDVInvokedUrlCommand*)command
+{
+ id message = [command.arguments objectAtIndex:0];
+ CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:message];
+
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+}
+
@end
diff --git a/iPhone/CordovaLib/Classes/CDVFile.h b/iPhone/CordovaLib/Classes/CDVFile.h
index 204c9f0..4862921 100755
--- a/iPhone/CordovaLib/Classes/CDVFile.h
+++ b/iPhone/CordovaLib/Classes/CDVFile.h
@@ -42,6 +42,8 @@ enum CDVFileSystemType {
};
typedef int CDVFileSystemType;
+extern NSString* const kCDVAssetsLibraryPrefix;
+
@interface CDVFile : CDVPlugin {
NSString* appDocsPath;
NSString* appLibraryPath;
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];
diff --git a/iPhone/CordovaLib/Classes/CDVFileTransfer.h b/iPhone/CordovaLib/Classes/CDVFileTransfer.h
index 76c6a95..f96bb7d 100755
--- a/iPhone/CordovaLib/Classes/CDVFileTransfer.h
+++ b/iPhone/CordovaLib/Classes/CDVFileTransfer.h
@@ -50,7 +50,8 @@ extern NSString* const kOptionsKeyCookie;
- (NSMutableDictionary*)createFileTransferError:(int)code
AndSource :(NSString*)source
AndTarget :(NSString*)target
- AndHttpStatus :(int)httpStatus;
+ AndHttpStatus :(int)httpStatus
+ AndBody :(NSString*)body;
@property (readonly) NSMutableDictionary* activeTransfers;
@end
@@ -64,8 +65,10 @@ extern NSString* const kOptionsKeyCookie;
@property (nonatomic, copy) NSString* objectId;
@property (nonatomic, copy) NSString* source;
@property (nonatomic, copy) NSString* target;
+@property (nonatomic, copy) NSString* mimeType;
@property (assign) int responseCode; // atomic
@property (nonatomic, assign) NSInteger bytesTransfered;
@property (nonatomic, assign) NSInteger bytesExpected;
+@property (nonatomic, assign) BOOL trustAllHosts;
@end;
diff --git a/iPhone/CordovaLib/Classes/CDVFileTransfer.m b/iPhone/CordovaLib/Classes/CDVFileTransfer.m
index b25177a..4ccdce6 100755
--- a/iPhone/CordovaLib/Classes/CDVFileTransfer.m
+++ b/iPhone/CordovaLib/Classes/CDVFileTransfer.m
@@ -19,7 +19,10 @@
#import "CDV.h"
-#include <CFNetwork/CFNetwork.h>
+#import <AssetsLibrary/ALAsset.h>
+#import <AssetsLibrary/ALAssetRepresentation.h>
+#import <AssetsLibrary/ALAssetsLibrary.h>
+#import <CFNetwork/CFNetwork.h>
@interface CDVFileTransfer ()
// Sets the requests headers for the request.
@@ -27,7 +30,7 @@
// Creates a delegate to handle an upload.
- (CDVFileTransferDelegate*)delegateForUploadCommand:(CDVInvokedUrlCommand*)command;
// Creates an NSData* for the file for the given upload arguments.
-- (NSData*)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command;
+- (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command;
@end
// Buffer size to use for streaming uploads.
@@ -87,7 +90,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
{
[req setValue:@"XMLHttpRequest" forHTTPHeaderField:@"X-Requested-With"];
- NSString* userAgent = [[self.webView request] valueForHTTPHeaderField:@"User-Agent"];
+ NSString* userAgent = [self.commandDelegate userAgent];
if (userAgent) {
[req setValue:userAgent forHTTPHeaderField:@"User-Agent"];
}
@@ -130,17 +133,10 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
NSString* fileName = [arguments objectAtIndex:3 withDefault:@"no-filename"];
NSString* mimeType = [arguments objectAtIndex:4 withDefault:nil];
NSDictionary* options = [arguments objectAtIndex:5 withDefault:nil];
- // NSString* trustAllHosts = (NSString*)[arguments objectAtIndex:6]; // allow self-signed certs
+ // BOOL trustAllHosts = [[arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs
BOOL chunkedMode = [[arguments objectAtIndex:7 withDefault:[NSNumber numberWithBool:YES]] boolValue];
NSDictionary* headers = [arguments objectAtIndex:8 withDefault:nil];
- // CFStreamCreateBoundPair crashes on iOS < 5.
- if (!IsAtLeastiOSVersion(@"5")) {
- // TODO(agrieve): See if it's okay license-wise to include the work-around code from:
- // http://developer.apple.com/library/ios/#samplecode/SimpleURLConnections/Listings/PostController_m.html
- chunkedMode = NO;
- }
-
CDVPluginResult* result = nil;
CDVFileTransferError errorCode = 0;
@@ -245,6 +241,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
{
NSString* source = [command.arguments objectAtIndex:0];
NSString* server = [command.arguments objectAtIndex:1];
+ BOOL trustAllHosts = [[command.arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs
NSString* objectId = [command.arguments objectAtIndex:9];
CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init];
@@ -255,29 +252,65 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
delegate.objectId = objectId;
delegate.source = source;
delegate.target = server;
+ delegate.trustAllHosts = trustAllHosts;
+
return delegate;
}
-- (NSData*)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command
+- (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command
{
NSString* target = (NSString*)[command.arguments objectAtIndex:0];
NSError* __autoreleasing err = nil;
- // Extract the path part out of a file: URL.
- NSString* filePath = [target hasPrefix:@"/"] ? [target copy] : [[NSURL URLWithString:target] path];
- // 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];
+ // 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) {
+ 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* fileData = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
+ [self uploadData:fileData command:command];
+ } else {
+ // 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];
+ }
+ };
+ 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];
+ };
+
+ ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+ [assetsLibrary assetForURL:[NSURL URLWithString:target] resultBlock:resultBlock failureBlock:failureBlock];
+ return;
+ } else {
+ // Extract the path part out of a file: URL.
+ NSString* filePath = [target hasPrefix:@"/"] ? [target copy] : [[NSURL URLWithString:target] path];
+
+ // 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);
+ if (err != nil) {
+ NSLog (@"Error opening file %@: %@", target, err);
+ }
+ [self uploadData:fileData command:command];
}
- return fileData;
}
- (void)upload:(CDVInvokedUrlCommand*)command
{
// fileData and req are split into helper functions to ease the unit testing of delegateForUpload.
- NSData* fileData = [self fileDataForUploadCommand:command];
+ // First, get the file data. This method will call `uploadData:command`.
+ [self fileDataForUploadCommand:command];
+}
+
+- (void)uploadData:(NSData*)fileData command:(CDVInvokedUrlCommand*)command
+{
NSURLRequest* req = [self requestForUploadCommand:command fileData:fileData];
if (req == nil) {
@@ -302,9 +335,9 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
if (delegate != nil) {
[delegate.connection cancel];
[activeTransfers removeObjectForKey:objectId];
-
- //delete uncomplete file
- NSFileManager *fileMgr = [NSFileManager defaultManager];
+
+ // delete uncomplete file
+ NSFileManager* fileMgr = [NSFileManager defaultManager];
[fileMgr removeItemAtPath:delegate.target error:nil];
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:CONNECTION_ABORTED AndSource:delegate.source AndTarget:delegate.target]];
@@ -317,8 +350,16 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
DLog(@"File Transfer downloading file...");
NSString* sourceUrl = [command.arguments objectAtIndex:0];
NSString* filePath = [command.arguments objectAtIndex:1];
- // NSString* trustAllHosts = (NSString*)[arguments objectAtIndex:6]; // allow self-signed certs
+ BOOL trustAllHosts = [[command.arguments objectAtIndex:2 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs
NSString* objectId = [command.arguments objectAtIndex:3];
+
+ // return unsupported result for assets-library URLs
+ if ([filePath hasPrefix:kCDVAssetsLibraryPrefix]) {
+ CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"download not supported for assets-library URLs."];
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ return;
+ }
+
CDVPluginResult* result = nil;
CDVFileTransferError errorCode = 0;
@@ -356,6 +397,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
delegate.objectId = objectId;
delegate.source = sourceUrl;
delegate.target = filePath;
+ delegate.trustAllHosts = trustAllHosts;
delegate.connection = [NSURLConnection connectionWithRequest:req delegate:delegate];
@@ -382,13 +424,15 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
AndSource:(NSString*)source
AndTarget:(NSString*)target
AndHttpStatus:(int)httpStatus
+ AndBody:(NSString*)body
{
- NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:4];
+ NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:5];
[result setObject:[NSNumber numberWithInt:code] forKey:@"code"];
[result setObject:source forKey:@"source"];
[result setObject:target forKey:@"target"];
[result setObject:[NSNumber numberWithInt:httpStatus] forKey:@"http_status"];
+ [result setObject:body forKey:@"body"];
NSLog(@"FileTransferError %@", result);
return result;
@@ -412,7 +456,8 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
NSString* uploadResponse = nil;
- BOOL downloadResponse;
+ NSString* downloadResponse = nil;
+ BOOL downloadWriteOK = NO;
NSMutableDictionary* uploadResult;
CDVPluginResult* result = nil;
NSError* __autoreleasing error = nil;
@@ -423,9 +468,10 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
NSLog(@"File Transfer Finished with response code %d", self.responseCode);
if (self.direction == CDV_TRANSFER_UPLOAD) {
+ uploadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
+
if ((self.responseCode >= 200) && (self.responseCode < 300)) {
// create dictionary to return FileUploadResult object
- uploadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
uploadResult = [NSMutableDictionary dictionaryWithCapacity:3];
if (uploadResponse != nil) {
[uploadResult setObject:uploadResponse forKey:@"response"];
@@ -434,7 +480,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
[uploadResult setObject:[NSNumber numberWithInt:self.responseCode] forKey:@"responseCode"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:uploadResult];
} else {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode]];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:uploadResponse]];
}
}
if (self.direction == CDV_TRANSFER_DOWNLOAD) {
@@ -450,11 +496,12 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
[[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:nil];
}
- downloadResponse = [self.responseData writeToFile:self.target options:NSDataWritingFileProtectionNone error:&error];
+ downloadWriteOK = [self.responseData writeToFile:self.target options:NSDataWritingFileProtectionNone error:&error];
- if (downloadResponse == NO) {
+ if (downloadWriteOK == NO) {
// send our results back
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:INVALID_URL_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode]];
+ downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:INVALID_URL_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
} else {
DLog(@"File Transfer Download success");
@@ -465,10 +512,13 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
}
@catch(id exception) {
// jump back to main thread
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode]];
+ downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
}
} else {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode]];
+ downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
}
}
@@ -480,23 +530,29 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
+ self.mimeType = [response MIMEType];
+
// required for iOS 4.3, for some reason; response is
// a plain NSURLResponse, not the HTTP subclass
- if (![response isKindOfClass:[NSHTTPURLResponse class]]) {
- self.responseCode = 403;
+ if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
+ NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
+
+ self.responseCode = [httpResponse statusCode];
self.bytesExpected = [response expectedContentLength];
- return;
+ } else if ([response.URL isFileURL]) {
+ NSDictionary* attr = [[NSFileManager defaultManager] attributesOfItemAtPath:[response.URL path] error:nil];
+ self.responseCode = 200;
+ self.bytesExpected = [attr[NSFileSize] longLongValue];
+ } else {
+ self.responseCode = 200;
+ self.bytesExpected = NSURLResponseUnknownLength;
}
-
- NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
-
- self.responseCode = [httpResponse statusCode];
- self.bytesExpected = [response expectedContentLength];
}
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
{
- CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode]];
+ NSString* body = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
+ CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:body]];
NSLog(@"File Transfer Error: %@", [error localizedDescription]);
@@ -537,33 +593,20 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
self.bytesTransfered = totalBytesWritten;
}
-/* TESTING ONLY CODE
-// use ONLY for testing with self signed certificates
-// uncomment and modify server name in connection didReceiveAuthenticationChallenge
-- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
+// for self signed certificates
+- (void)connection:(NSURLConnection*)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge
{
- return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
-}
-
-- (void)connection:(NSURLConnection *) connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge
-{
- if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
- {
- //NSLog(@"challenge host: %@", challenge.protectionSpace.host);
- // we only trust our own domain
- if ([challenge.protectionSpace.host isEqualToString:@"serverName.domain.com"]){
- NSURLCredential* myCredential = [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust];
-
- [challenge.sender useCredential:myCredential forAuthenticationChallenge:challenge];
-
+ if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
+ if (self.trustAllHosts) {
+ NSURLCredential* credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
+ [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}
+ [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
+ } else {
+ [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
}
-
- [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
-// uncomment the above two methods for testing servers with self signed certificates
-// END TESTING ONLY CODE
- */
+
- (id)init
{
if ((self = [super init])) {
diff --git a/iPhone/CordovaLib/Classes/CDVInAppBrowser.h b/iPhone/CordovaLib/Classes/CDVInAppBrowser.h
index 51199ed..9ff460a 100755
--- a/iPhone/CordovaLib/Classes/CDVInAppBrowser.h
+++ b/iPhone/CordovaLib/Classes/CDVInAppBrowser.h
@@ -31,7 +31,7 @@
@end
-@interface CDVInAppBrowser : CDVPlugin <CDVInAppBrowserNavigationDelegate>{}
+@interface CDVInAppBrowser : CDVPlugin <CDVInAppBrowserNavigationDelegate>
@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController;
@property (nonatomic, copy) NSString* callbackId;
@@ -41,7 +41,13 @@
@end
-@interface CDVInAppBrowserViewController : UIViewController <UIWebViewDelegate>{}
+@interface CDVInAppBrowserViewController : UIViewController <UIWebViewDelegate>{
+ @private
+ NSURL* _requestedURL;
+ NSString* _userAgent;
+ NSString* _prevUserAgent;
+ NSInteger _userAgentLockToken;
+}
@property (nonatomic, strong) IBOutlet UIWebView* webView;
@property (nonatomic, strong) IBOutlet UIBarButtonItem* closeButton;
@@ -53,19 +59,26 @@
@property (nonatomic, weak) id <CDVScreenOrientationDelegate> orientationDelegate;
@property (nonatomic, weak) id <CDVInAppBrowserNavigationDelegate> navigationDelegate;
-@property (nonatomic, strong) NSString* userAgent;
- (void)close;
- (void)navigateTo:(NSURL*)url;
- (void)showLocationBar:(BOOL)show;
-- (id)initWithUserAgent:(NSString*)userAgent;
+- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent;
@end
@interface CDVInAppBrowserOptions : NSObject {}
@property (nonatomic, assign) BOOL location;
+@property (nonatomic, copy) NSString* presentationstyle;
+@property (nonatomic, copy) NSString* transitionstyle;
+
+@property (nonatomic, assign) BOOL enableviewportscale;
+@property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction;
+@property (nonatomic, assign) BOOL allowinlinemediaplayback;
+@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction;
+@property (nonatomic, assign) BOOL suppressesincrementalrendering;
+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options;
diff --git a/iPhone/CordovaLib/Classes/CDVInAppBrowser.m b/iPhone/CordovaLib/Classes/CDVInAppBrowser.m
index 22fd1fc..14671a5 100755
--- a/iPhone/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/iPhone/CordovaLib/Classes/CDVInAppBrowser.m
@@ -19,7 +19,7 @@
#import "CDVInAppBrowser.h"
#import "CDVPluginResult.h"
-#import "CDVViewController.h"
+#import "CDVUserAgentUtil.h"
#define kInAppBrowserTargetSelf @"_self"
#define kInAppBrowserTargetSystem @"_system"
@@ -91,8 +91,8 @@
- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options
{
if (self.inAppBrowserViewController == nil) {
- NSString* originalUA = [CDVViewController originalUserAgent];
- self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA];
+ NSString* originalUA = [CDVUserAgentUtil originalUserAgent];
+ self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA prevUserAgent:[self.commandDelegate userAgent]];
self.inAppBrowserViewController.navigationDelegate = self;
if ([self.viewController conformsToProtocol:@protocol(CDVScreenOrientationDelegate)]) {
@@ -103,6 +103,37 @@
CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options];
[self.inAppBrowserViewController showLocationBar:browserOptions.location];
+ // Set Presentation Style
+ UIModalPresentationStyle presentationStyle = UIModalPresentationFullScreen; // default
+ if (browserOptions.presentationstyle != nil) {
+ if ([browserOptions.presentationstyle isEqualToString:@"pagesheet"]) {
+ presentationStyle = UIModalPresentationPageSheet;
+ } else if ([browserOptions.presentationstyle isEqualToString:@"formsheet"]) {
+ presentationStyle = UIModalPresentationFormSheet;
+ }
+ }
+ self.inAppBrowserViewController.modalPresentationStyle = presentationStyle;
+
+ // Set Transition Style
+ UIModalTransitionStyle transitionStyle = UIModalTransitionStyleCoverVertical; // default
+ if (browserOptions.transitionstyle != nil) {
+ if ([browserOptions.transitionstyle isEqualToString:@"fliphorizontal"]) {
+ transitionStyle = UIModalTransitionStyleFlipHorizontal;
+ } else if ([browserOptions.transitionstyle isEqualToString:@"crossdissolve"]) {
+ transitionStyle = UIModalTransitionStyleCrossDissolve;
+ }
+ }
+ self.inAppBrowserViewController.modalTransitionStyle = transitionStyle;
+
+ // UIWebView options
+ self.inAppBrowserViewController.webView.scalesPageToFit = browserOptions.enableviewportscale;
+ self.inAppBrowserViewController.webView.mediaPlaybackRequiresUserAction = browserOptions.mediaplaybackrequiresuseraction;
+ self.inAppBrowserViewController.webView.allowsInlineMediaPlayback = browserOptions.allowinlinemediaplayback;
+ if (IsAtLeastiOSVersion(@"6.0")) {
+ self.inAppBrowserViewController.webView.keyboardDisplayRequiresUserAction = browserOptions.keyboarddisplayrequiresuseraction;
+ self.inAppBrowserViewController.webView.suppressesIncrementalRendering = browserOptions.suppressesincrementalrendering;
+ }
+
if (self.viewController.modalViewController != self.inAppBrowserViewController) {
[self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES];
}
@@ -111,18 +142,7 @@
- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options
{
- BOOL passesWhitelist = YES;
-
- if ([self.viewController isKindOfClass:[CDVViewController class]]) {
- CDVViewController* vc = (CDVViewController*)self.viewController;
- if ([vc.whitelist schemeIsAllowed:[url scheme]]) {
- passesWhitelist = [vc.whitelist URLIsAllowed:url];
- }
- } else { // something went wrong, we can't get the whitelist
- passesWhitelist = NO;
- }
-
- if (passesWhitelist) {
+ if ([self.commandDelegate URLIsWhitelisted:url]) {
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
} else { // this assumes the InAppBrowser can be excepted from the white-list
@@ -172,6 +192,9 @@
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
}
+ // Don't recycle the ViewController since it may be consuming a lot of memory.
+ // Also - this is required for the PDF/User-Agent bug work-around.
+ self.inAppBrowserViewController = nil;
}
@end
@@ -180,11 +203,12 @@
@implementation CDVInAppBrowserViewController
-- (id)initWithUserAgent:(NSString*)userAgent
+- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent
{
self = [super init];
if (self != nil) {
- self.userAgent = userAgent;
+ _userAgent = userAgent;
+ _prevUserAgent = prevUserAgent;
[self createViews];
}
@@ -199,31 +223,23 @@
webViewBounds.size.height -= FOOTER_HEIGHT;
- if (!self.webView) {
- // setting the UserAgent must occur before the UIWebView is instantiated.
- // This is read per instantiation, so it does not affect the main Cordova UIWebView
- NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:self.userAgent, @"UserAgent", nil];
- [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
-
- self.webView = [[UIWebView alloc] initWithFrame:webViewBounds];
- self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
-
- [self.view addSubview:self.webView];
- [self.view sendSubviewToBack:self.webView];
-
- self.webView.delegate = self;
- self.webView.scalesPageToFit = TRUE;
- self.webView.backgroundColor = [UIColor whiteColor];
-
- self.webView.clearsContextBeforeDrawing = YES;
- self.webView.clipsToBounds = YES;
- self.webView.contentMode = UIViewContentModeScaleToFill;
- self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
- self.webView.multipleTouchEnabled = YES;
- self.webView.opaque = YES;
- self.webView.scalesPageToFit = NO;
- self.webView.userInteractionEnabled = YES;
- }
+ self.webView = [[UIWebView alloc] initWithFrame:webViewBounds];
+ self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
+
+ [self.view addSubview:self.webView];
+ [self.view sendSubviewToBack:self.webView];
+
+ self.webView.delegate = self;
+ self.webView.backgroundColor = [UIColor whiteColor];
+
+ self.webView.clearsContextBeforeDrawing = YES;
+ self.webView.clipsToBounds = YES;
+ self.webView.contentMode = UIViewContentModeScaleToFill;
+ self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+ self.webView.multipleTouchEnabled = YES;
+ self.webView.opaque = YES;
+ self.webView.scalesPageToFit = NO;
+ self.webView.userInteractionEnabled = YES;
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
self.spinner.alpha = 1.000;
@@ -346,11 +362,14 @@
- (void)viewDidUnload
{
[self.webView loadHTMLString:nil baseURL:nil];
+ [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
[super viewDidUnload];
}
- (void)close
{
+ [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
+
if ([self respondsToSelector:@selector(presentingViewController)]) {
[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
} else {
@@ -366,7 +385,17 @@
{
NSURLRequest* request = [NSURLRequest requestWithURL:url];
- [self.webView loadRequest:request];
+ _requestedURL = url;
+
+ if (_userAgentLockToken != 0) {
+ [self.webView loadRequest:request];
+ } else {
+ [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
+ _userAgentLockToken = lockToken;
+ [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken];
+ [self.webView loadRequest:request];
+ }];
+ }
}
- (void)goBack:(id)sender
@@ -392,7 +421,11 @@
[self.spinner startAnimating];
if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStart:)]) {
- [self.navigationDelegate browserLoadStart:theWebView.request.URL];
+ NSURL* url = theWebView.request.URL;
+ if (url == nil) {
+ url = _requestedURL;
+ }
+ [self.navigationDelegate browserLoadStart:url];
}
}
@@ -406,8 +439,25 @@
[self.spinner stopAnimating];
+ // Work around a bug where the first time a PDF is opened, all UIWebViews
+ // reload their User-Agent from NSUserDefaults.
+ // This work-around makes the following assumptions:
+ // 1. The app has only a single Cordova Webview. If not, then the app should
+ // take it upon themselves to load a PDF in the background as a part of
+ // their start-up flow.
+ // 2. That the PDF does not require any additional network requests. We change
+ // the user-agent here back to that of the CDVViewController, so requests
+ // 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"]];
+ if (isPDF) {
+ [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken];
+ }
+
if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStop:)]) {
- [self.navigationDelegate browserLoadStop:theWebView.request.URL];
+ NSURL* url = theWebView.request.URL;
+ [self.navigationDelegate browserLoadStop:url];
}
}
@@ -460,6 +510,12 @@
if (self = [super init]) {
// default values
self.location = YES;
+
+ self.enableviewportscale = NO;
+ self.mediaplaybackrequiresuseraction = NO;
+ self.allowinlinemediaplayback = NO;
+ self.keyboarddisplayrequiresuseraction = YES;
+ self.suppressesincrementalrendering = NO;
}
return self;
@@ -478,12 +534,22 @@
if ([keyvalue count] == 2) {
NSString* key = [[keyvalue objectAtIndex:0] lowercaseString];
- NSString* value = [keyvalue objectAtIndex:1];
- BOOL valueBool = [[value lowercaseString] isEqualToString:@"yes"];
+ NSString* value = [[keyvalue objectAtIndex:1] lowercaseString];
+
+ BOOL isBoolean = [value isEqualToString:@"yes"] || [value isEqualToString:@"no"];
+ NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init];
+ [numberFormatter setAllowsFloats:YES];
+ BOOL isNumber = [numberFormatter numberFromString:value] != nil;
// set the property according to the key name
if ([obj respondsToSelector:NSSelectorFromString(key)]) {
- [obj setValue:[NSNumber numberWithBool:valueBool] forKey:key];
+ if (isNumber) {
+ [obj setValue:[numberFormatter numberFromString:value] forKey:key];
+ } else if (isBoolean) {
+ [obj setValue:[NSNumber numberWithBool:[value isEqualToString:@"yes"]] forKey:key];
+ } else {
+ [obj setValue:value forKey:key];
+ }
}
}
}
diff --git a/iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.m b/iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.m
index 833baad..6c7a856 100755
--- a/iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.m
+++ b/iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.m
@@ -18,7 +18,8 @@
*/
#import "CDVInvokedUrlCommand.h"
-#import "JSONKit.h"
+#import "CDVJSON.h"
+#import "NSData+Base64.h"
@implementation CDVInvokedUrlCommand
@@ -58,9 +59,36 @@
_className = className;
_methodName = methodName;
}
+ [self massageArguments];
return self;
}
+- (void)massageArguments
+{
+ NSMutableArray* newArgs = nil;
+
+ for (NSUInteger i = 0, count = [_arguments count]; i < count; ++i) {
+ id arg = [_arguments objectAtIndex:i];
+ if (![arg isKindOfClass:[NSDictionary class]]) {
+ continue;
+ }
+ NSDictionary* dict = arg;
+ NSString* type = [dict objectForKey:@"CDVType"];
+ if (!type || ![type isEqualToString:@"ArrayBuffer"]) {
+ continue;
+ }
+ NSString* data = [dict objectForKey:@"data"];
+ if (!data) {
+ continue;
+ }
+ if (newArgs == nil) {
+ newArgs = [NSMutableArray arrayWithArray:_arguments];
+ _arguments = newArgs;
+ }
+ [newArgs replaceObjectAtIndex:i withObject:[NSData dataFromBase64String:data]];
+ }
+}
+
- (void)legacyArguments:(NSMutableArray**)legacyArguments andDict:(NSMutableDictionary**)legacyDict
{
NSMutableArray* newArguments = [NSMutableArray arrayWithArray:_arguments];
diff --git a/iPhone/CordovaLib/Classes/CDVCordovaView.h b/iPhone/CordovaLib/Classes/CDVJSON.h
index 6318b21..eaa895e 100755
--- a/iPhone/CordovaLib/Classes/CDVCordovaView.h
+++ b/iPhone/CordovaLib/Classes/CDVJSON.h
@@ -17,7 +17,14 @@
under the License.
*/
-#import <UIKit/UIKit.h>
+@interface NSArray (CDVJSONSerializing)
+- (NSString*)JSONString;
+@end
+
+@interface NSDictionary (CDVJSONSerializing)
+- (NSString*)JSONString;
+@end
-@interface CDVCordovaView : UIWebView {}
+@interface NSString (CDVJSONSerializing)
+- (id)JSONObject;
@end
diff --git a/iPhone/CordovaLib/Classes/CDVJSON.m b/iPhone/CordovaLib/Classes/CDVJSON.m
new file mode 100755
index 0000000..78267e5
--- /dev/null
+++ b/iPhone/CordovaLib/Classes/CDVJSON.m
@@ -0,0 +1,77 @@
+/*
+ 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 "CDVJSON.h"
+#import <Foundation/NSJSONSerialization.h>
+
+@implementation NSArray (CDVJSONSerializing)
+
+- (NSString*)JSONString
+{
+ NSError* error = nil;
+ NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+
+ if (error != nil) {
+ NSLog(@"NSArray JSONString error: %@", [error localizedDescription]);
+ return nil;
+ } else {
+ return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+ }
+}
+
+@end
+
+@implementation NSDictionary (CDVJSONSerializing)
+
+- (NSString*)JSONString
+{
+ NSError* error = nil;
+ NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+
+ if (error != nil) {
+ NSLog(@"NSDictionary JSONString error: %@", [error localizedDescription]);
+ return nil;
+ } else {
+ return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+ }
+}
+
+@end
+
+@implementation NSString (CDVJSONSerializing)
+
+- (id)JSONObject
+{
+ NSError* error = nil;
+ id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding]
+ options:kNilOptions
+ error:&error];
+
+ if (error != nil) {
+ NSLog(@"NSString JSONObject error: %@", [error localizedDescription]);
+ }
+
+ return object;
+}
+
+@end
diff --git a/iPhone/CordovaLib/Classes/CDVLocalStorage.h b/iPhone/CordovaLib/Classes/CDVLocalStorage.h
index e5e3112..cc6613f 100755
--- a/iPhone/CordovaLib/Classes/CDVLocalStorage.h
+++ b/iPhone/CordovaLib/Classes/CDVLocalStorage.h
@@ -22,7 +22,7 @@
#define kCDVLocalStorageErrorDomain @"kCDVLocalStorageErrorDomain"
#define kCDVLocalStorageFileOperationError 1
-@interface CDVLocalStorage : CDVPlugin <UIWebViewDelegate>
+@interface CDVLocalStorage : CDVPlugin
@property (nonatomic, readonly, strong) NSMutableArray* backupInfo;
diff --git a/iPhone/CordovaLib/Classes/CDVLocalStorage.m b/iPhone/CordovaLib/Classes/CDVLocalStorage.m
index 217f611..68175f1 100755
--- a/iPhone/CordovaLib/Classes/CDVLocalStorage.m
+++ b/iPhone/CordovaLib/Classes/CDVLocalStorage.m
@@ -31,21 +31,13 @@
@synthesize backupInfo, webviewDelegate;
-- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView settings:(NSDictionary*)classSettings
+- (void)pluginInitialize
{
- self = (CDVLocalStorage*)[super initWithWebView:theWebView settings:classSettings];
- if (self) {
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive)
- name:UIApplicationWillResignActiveNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive)
+ name:UIApplicationWillResignActiveNotification object:nil];
+ BOOL cloudBackup = [@"cloud" isEqualToString:self.commandDelegate.settings[@"BackupWebStorage"]];
- self.backupInfo = [[self class] createBackupInfoWithCloudBackup:[(NSString*)[classSettings objectForKey:@"backupType"] isEqualToString:@"cloud"]];
-
- // over-ride current webview delegate (for restore reasons)
- self.webviewDelegate = theWebView.delegate;
- theWebView.delegate = self;
- }
-
- return self;
+ self.backupInfo = [[self class] createBackupInfoWithCloudBackup:cloudBackup];
}
#pragma mark -
@@ -411,37 +403,9 @@
[self onResignActive];
}
-#pragma mark -
-#pragma mark UIWebviewDelegate implementation and forwarding
-
-- (void)webViewDidStartLoad:(UIWebView*)theWebView
+- (void)onReset
{
[self restore:nil];
-
- return [self.webviewDelegate webViewDidStartLoad:theWebView];
-}
-
-- (void)webViewDidFinishLoad:(UIWebView*)theWebView
-{
- return [self.webviewDelegate webViewDidFinishLoad:theWebView];
-}
-
-- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
-{
- return [self.webviewDelegate webView:theWebView didFailLoadWithError:error];
-}
-
-- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
-{
- return [self.webviewDelegate webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType];
-}
-
-#pragma mark -
-#pragma mark Over-rides
-
-- (void)dealloc
-{
- [[NSNotificationCenter defaultCenter] removeObserver:self]; // this will remove all notification unless added using addObserverForName:object:queue:usingBlock:
}
@end
diff --git a/iPhone/CordovaLib/Classes/CDVLocation.m b/iPhone/CordovaLib/Classes/CDVLocation.m
index 9814f35..07af30e 100755
--- a/iPhone/CordovaLib/Classes/CDVLocation.m
+++ b/iPhone/CordovaLib/Classes/CDVLocation.m
@@ -18,7 +18,6 @@
*/
#import "CDVLocation.h"
-#import "CDVViewController.h"
#import "NSArray+Comparisons.h"
#pragma mark Constants
@@ -477,17 +476,8 @@
// helper method to check the orientation and start updating headings
- (void)startHeadingWithFilter:(CLLocationDegrees)filter
{
- if ([self.locationManager respondsToSelector:@selector(headingOrientation)]) {
- UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];
- if (currentOrientation != UIDeviceOrientationUnknown) {
- CDVViewController* cdvViewController = (CDVViewController*)self.viewController;
-
- if ([cdvViewController supportsOrientation:currentOrientation]) {
- self.locationManager.headingOrientation = (CLDeviceOrientation)currentOrientation;
- // FYI UIDeviceOrientation and CLDeviceOrientation enums are currently the same
- }
- }
- }
+ // FYI UIDeviceOrientation and CLDeviceOrientation enums are currently the same
+ self.locationManager.headingOrientation = (CLDeviceOrientation)self.viewController.interfaceOrientation;
self.locationManager.headingFilter = filter;
[self.locationManager startUpdatingHeading];
self.headingData.headingStatus = HEADINGSTARTING;
diff --git a/iPhone/CordovaLib/Classes/CDVPlugin.h b/iPhone/CordovaLib/Classes/CDVPlugin.h
index 8c59a2b..f5b50eb 100755
--- a/iPhone/CordovaLib/Classes/CDVPlugin.h
+++ b/iPhone/CordovaLib/Classes/CDVPlugin.h
@@ -23,6 +23,7 @@
#import "NSMutableArray+QueueAdditions.h"
#import "CDVCommandDelegate.h"
+#define CDVPageDidLoadNotification @"CDVPageDidLoadNotification"
#define CDVPluginHandleOpenURLNotification @"CDVPluginHandleOpenURLNotification"
#define CDVPluginResetNotification @"CDVPluginResetNotification"
#define CDVLocalNotification @"CDVLocalNotification"
@@ -30,14 +31,13 @@
@interface CDVPlugin : NSObject {}
@property (nonatomic, weak) UIWebView* webView;
-@property (nonatomic, strong) NSDictionary* settings;
@property (nonatomic, weak) UIViewController* viewController;
@property (nonatomic, weak) id <CDVCommandDelegate> commandDelegate;
@property (readonly, assign) BOOL hasPendingOperation;
-- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView settings:(NSDictionary*)classSettings;
- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView;
+- (void)pluginInitialize;
- (void)handleOpenURL:(NSNotification*)notification;
- (void)onAppTerminate;
diff --git a/iPhone/CordovaLib/Classes/CDVPlugin.m b/iPhone/CordovaLib/Classes/CDVPlugin.m
index 53023c7..a42d241 100755
--- a/iPhone/CordovaLib/Classes/CDVPlugin.m
+++ b/iPhone/CordovaLib/Classes/CDVPlugin.m
@@ -26,16 +26,12 @@
@end
@implementation CDVPlugin
-@synthesize webView, settings, viewController, commandDelegate, hasPendingOperation;
+@synthesize webView, viewController, commandDelegate, hasPendingOperation;
+// Do not override these methods. Use pluginInitialize instead.
- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView settings:(NSDictionary*)classSettings
{
- self = [self initWithWebView:theWebView];
- if (self) {
- self.settings = classSettings;
- self.hasPendingOperation = NO;
- }
- return self;
+ return [self initWithWebView:theWebView];
}
- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView
@@ -48,26 +44,29 @@
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReset) name:CDVPluginResetNotification object:nil];
self.webView = theWebView;
-
- // You can listen to more app notifications, see:
- // http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006728-CH3-DontLinkElementID_4
-
- /*
- // NOTE: if you want to use these, make sure you uncomment the corresponding notification handler
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
-
- // Added in 2.3.0+
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:CDVLocalNotification object:nil];
-
- */
}
return self;
}
+- (void)pluginInitialize
+{
+ // You can listen to more app notifications, see:
+ // http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006728-CH3-DontLinkElementID_4
+
+ // NOTE: if you want to use these, make sure you uncomment the corresponding notification handler
+
+ // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil];
+ // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil];
+ // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
+ // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
+
+ // Added in 2.3.0
+ // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:CDVLocalNotification object:nil];
+
+ // Added in 2.5.0
+ // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad:) name:CDVPageDidLoadNotification object:nil];
+}
+
- (void)dispose
{
viewController = nil;
@@ -140,9 +139,9 @@
}
// default implementation does nothing, ideally, we are not registered for notification if we aren't going to do anything.
-//- (void)didReceiveLocalNotification:(NSNotification *)notification
-//{
+// - (void)didReceiveLocalNotification:(NSNotification *)notification
+// {
// // UILocalNotification* localNotification = [notification object]; // get the payload as a LocalNotification
-//}
+// }
@end
diff --git a/iPhone/CordovaLib/Classes/CDVPluginResult.h b/iPhone/CordovaLib/Classes/CDVPluginResult.h
index 6dd7d45..8683205 100755
--- a/iPhone/CordovaLib/Classes/CDVPluginResult.h
+++ b/iPhone/CordovaLib/Classes/CDVPluginResult.h
@@ -44,7 +44,9 @@ typedef enum {
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArray:(NSArray*)theMessage;
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsInt:(int)theMessage;
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDouble:(double)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage;
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage;
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode;
+ (void)setVerbose:(BOOL)verbose;
diff --git a/iPhone/CordovaLib/Classes/CDVPluginResult.m b/iPhone/CordovaLib/Classes/CDVPluginResult.m
index 5343dce..d9ba08f 100755
--- a/iPhone/CordovaLib/Classes/CDVPluginResult.m
+++ b/iPhone/CordovaLib/Classes/CDVPluginResult.m
@@ -18,8 +18,9 @@
*/
#import "CDVPluginResult.h"
-#import "JSONKit.h"
+#import "CDVJSON.h"
#import "CDVDebug.h"
+#import "NSData+Base64.h"
@interface CDVPluginResult ()
@@ -88,11 +89,26 @@ static NSArray* org_apache_cordova_CommandStatusMsgs;
return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithDouble:theMessage]];
}
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage
+{
+ return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithBool:theMessage]];
+}
+
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage
{
return [[self alloc] initWithStatus:statusOrdinal message:theMessage];
}
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage
+{
+ NSDictionary* arrDict = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"ArrayBuffer", @"CDVType",
+ [theMessage base64EncodedString], @"data",
+ nil];
+
+ return [[self alloc] initWithStatus:statusOrdinal message:arrDict];
+}
+
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode
{
NSDictionary* errDict = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:errorCode] forKey:@"code"];
@@ -107,11 +123,23 @@ static NSArray* org_apache_cordova_CommandStatusMsgs;
- (NSString*)toJSONString
{
- NSString* resultString = [[NSDictionary dictionaryWithObjectsAndKeys:
- self.status, @"status",
- self.message ? self. message:[NSNull null], @"message",
- self.keepCallback, @"keepCallback",
- nil] cdvjk_JSONString];
+ NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
+ self.status, @"status",
+ self.message ? self. message:[NSNull null], @"message",
+ self.keepCallback, @"keepCallback",
+ nil];
+
+ NSError* error = nil;
+ NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dict
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+ NSString* resultString = nil;
+
+ if (error != nil) {
+ NSLog(@"toJSONString error: %@", [error localizedDescription]);
+ } else {
+ resultString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+ }
if ([[self class] isVerbose]) {
NSLog(@"PluginResult:toJSONString - %@", resultString);
diff --git a/iPhone/CordovaLib/Classes/CDVSound.h b/iPhone/CordovaLib/Classes/CDVSound.h
index 6551621..8dcf98e 100755
--- a/iPhone/CordovaLib/Classes/CDVSound.h
+++ b/iPhone/CordovaLib/Classes/CDVSound.h
@@ -98,7 +98,13 @@ typedef NSUInteger CDVMediaMsg;
- (BOOL)hasAudioSession;
// helper methods
-- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId;
+- (NSURL*)urlForRecording:(NSString*)resourcePath;
+- (NSURL*)urlForPlaying:(NSString*)resourcePath;
+- (NSURL*)urlForResource:(NSString*)resourcePath CDV_DEPRECATED(2.5, "Use specific api for playing or recording");
+
+- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId CDV_DEPRECATED(2.5, "Use updated audioFileForResource api");
+
+- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId doValidation:(BOOL)bValidate forRecording:(BOOL)bRecord;
- (BOOL)prepareToPlay:(CDVAudioFile*)audioFile withId:(NSString*)mediaId;
- (NSString*)createMediaErrorWithCode:(CDVMediaError)code message:(NSString*)message;
diff --git a/iPhone/CordovaLib/Classes/CDVSound.m b/iPhone/CordovaLib/Classes/CDVSound.m
index f7a3adf..99515d7 100755
--- a/iPhone/CordovaLib/Classes/CDVSound.m
+++ b/iPhone/CordovaLib/Classes/CDVSound.m
@@ -18,19 +18,18 @@
*/
#import "CDVSound.h"
-#import "CDVViewController.h"
#import "NSArray+Comparisons.h"
+#import "CDVJSON.h"
#define DOCUMENTS_SCHEME_PREFIX @"documents://"
#define HTTP_SCHEME_PREFIX @"http://"
#define HTTPS_SCHEME_PREFIX @"https://"
+#define RECORDING_WAV @"wav"
@implementation CDVSound
@synthesize soundCache, avSession;
-// Maps a url for a resource path
-// "Naked" resource paths are assumed to be from the www folder as its base
- (NSURL*)urlForResource:(NSString*)resourcePath
{
NSURL* resourceURL = nil;
@@ -43,7 +42,8 @@
NSLog(@"Will use resource '%@' from the Internet.", resourcePath);
resourceURL = [NSURL URLWithString:resourcePath];
} else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) {
- filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", [CDVViewController applicationDocumentsDirectory]]];
+ NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
+ filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]];
NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath);
} else {
// attempt to find file path in www directory
@@ -70,9 +70,101 @@
return resourceURL;
}
-// Creates or gets the cached audio file resource object
+// Maps a url for a resource path for recording
+- (NSURL*)urlForRecording:(NSString*)resourcePath
+{
+ NSURL* resourceURL = nil;
+ NSString* filePath = nil;
+ NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
+
+ // first check for correct extension
+ if ([[resourcePath pathExtension] caseInsensitiveCompare:RECORDING_WAV] != NSOrderedSame) {
+ resourceURL = nil;
+ NSLog(@"Resource for recording must have %@ extension", RECORDING_WAV);
+ } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) {
+ // try to find Documents:// resources
+ filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]];
+ NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath);
+ } else {
+ // if resourcePath is not from FileSystem put in tmp dir, else attempt to use provided resource path
+ NSString* tmpPath = [NSTemporaryDirectory ()stringByStandardizingPath];
+ BOOL isTmp = [resourcePath rangeOfString:tmpPath].location != NSNotFound;
+ BOOL isDoc = [resourcePath rangeOfString:docsPath].location != NSNotFound;
+ if (!isTmp && !isDoc) {
+ // put in temp dir
+ filePath = [NSString stringWithFormat:@"%@/%@", tmpPath, resourcePath];
+ } else {
+ filePath = resourcePath;
+ }
+ }
+
+ if (filePath != nil) {
+ // create resourceURL
+ resourceURL = [NSURL fileURLWithPath:filePath];
+ }
+ return resourceURL;
+}
+
+// Maps a url for a resource path for playing
+// "Naked" resource paths are assumed to be from the www folder as its base
+- (NSURL*)urlForPlaying:(NSString*)resourcePath
+{
+ NSURL* resourceURL = nil;
+ NSString* filePath = nil;
+
+ // first try to find HTTP:// or Documents:// resources
+
+ if ([resourcePath hasPrefix:HTTP_SCHEME_PREFIX] || [resourcePath hasPrefix:HTTPS_SCHEME_PREFIX]) {
+ // if it is a http url, use it
+ NSLog(@"Will use resource '%@' from the Internet.", resourcePath);
+ resourceURL = [NSURL URLWithString:resourcePath];
+ } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) {
+ NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
+ filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]];
+ NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath);
+ } else {
+ // attempt to find file path in www directory or LocalFileSystem.TEMPORARY directory
+ filePath = [self.commandDelegate pathForResource:resourcePath];
+ if (filePath == nil) {
+ // see if this exists in the documents/temp directory from a previous recording
+ NSString* testPath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory ()stringByStandardizingPath], resourcePath];
+ if ([[NSFileManager defaultManager] fileExistsAtPath:testPath]) {
+ // inefficient as existence will be checked again below but only way to determine if file exists from previous recording
+ filePath = testPath;
+ NSLog(@"Will attempt to use file resource from LocalFileSystem.TEMPORARY directory");
+ } else {
+ // attempt to use path provided
+ filePath = resourcePath;
+ NSLog(@"Will attempt to use file resource '%@'", filePath);
+ }
+ } else {
+ NSLog(@"Found resource '%@' in the web folder.", filePath);
+ }
+ }
+ // check that file exists for all but HTTP_SHEME_PREFIX
+ if (filePath != nil) {
+ // create resourceURL
+ resourceURL = [NSURL fileURLWithPath:filePath];
+ // try to access file
+ NSFileManager* fMgr = [NSFileManager defaultManager];
+ if (![fMgr fileExistsAtPath:filePath]) {
+ resourceURL = nil;
+ NSLog(@"Unknown resource '%@'", resourcePath);
+ }
+ }
+
+ return resourceURL;
+}
+
- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId
{
+ // will maintain backwards compatibility with original implementation
+ return [self audioFileForResource:resourcePath withId:mediaId doValidation:YES forRecording:NO];
+}
+
+// Creates or gets the cached audio file resource object
+- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId doValidation:(BOOL)bValidate forRecording:(BOOL)bRecord
+{
BOOL bError = NO;
CDVMediaError errcode = MEDIA_ERR_NONE_SUPPORTED;
NSString* errMsg = @"";
@@ -87,31 +179,37 @@
}
if (audioFile == nil) {
// validate resourcePath and create
-
if ((resourcePath == nil) || ![resourcePath isKindOfClass:[NSString class]] || [resourcePath isEqualToString:@""]) {
bError = YES;
errcode = MEDIA_ERR_ABORTED;
errMsg = @"invalid media src argument";
} else {
- resourceURL = [self urlForResource:resourcePath];
+ audioFile = [[CDVAudioFile alloc] init];
+ audioFile.resourcePath = resourcePath;
+ audioFile.resourceURL = nil; // validate resourceURL when actually play or record
+ [[self soundCache] setObject:audioFile forKey:mediaId];
+ }
+ }
+ if (bValidate && (audioFile.resourceURL == nil)) {
+ if (bRecord) {
+ resourceURL = [self urlForRecording:resourcePath];
+ } else {
+ resourceURL = [self urlForPlaying:resourcePath];
}
-
if (resourceURL == nil) {
bError = YES;
errcode = MEDIA_ERR_ABORTED;
errMsg = [NSString stringWithFormat:@"Cannot use audio file from resource '%@'", resourcePath];
- }
- if (bError) {
- // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, errcode];
- jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:errcode message:errMsg]];
- [self.commandDelegate evalJs:jsString];
} else {
- audioFile = [[CDVAudioFile alloc] init];
- audioFile.resourcePath = resourcePath;
audioFile.resourceURL = resourceURL;
- [[self soundCache] setObject:audioFile forKey:mediaId];
}
}
+
+ if (bError) {
+ jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:errcode message:errMsg]];
+ [self.commandDelegate evalJs:jsString];
+ }
+
return audioFile;
}
@@ -141,7 +239,7 @@
[errorDict setObject:[NSNumber numberWithUnsignedInt:code] forKey:@"code"];
[errorDict setObject:message ? message:@"" forKey:@"message"];
- return [errorDict cdvjk_JSONString];
+ return [errorDict JSONString];
}
- (void)create:(CDVInvokedUrlCommand*)command
@@ -149,7 +247,7 @@
NSString* mediaId = [command.arguments objectAtIndex:0];
NSString* resourcePath = [command.arguments objectAtIndex:1];
- CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId];
+ CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId doValidation:NO forRecording:NO];
if (audioFile == nil) {
NSString* errorMessage = [NSString stringWithFormat:@"Failed to initialize Media file with path %@", resourcePath];
@@ -193,9 +291,8 @@
BOOL bError = NO;
NSString* jsString = nil;
- CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId];
-
- if (audioFile != nil) {
+ CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId doValidation:YES forRecording:NO];
+ if ((audioFile != nil) && (audioFile.resourceURL != nil)) {
if (audioFile.player == nil) {
bError = [self prepareToPlay:audioFile withId:mediaId];
}
@@ -274,7 +371,12 @@
if ([resourceURL isFileURL]) {
audioFile.player = [[CDVAudioPlayer alloc] initWithContentsOfURL:resourceURL error:&playerError];
} else {
- NSURLRequest* request = [NSURLRequest requestWithURL:resourceURL];
+ NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:resourceURL];
+ NSString* userAgent = [self.commandDelegate userAgent];
+ if (userAgent) {
+ [request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
+ }
+
NSURLResponse* __autoreleasing response = nil;
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&playerError];
if (playerError) {
@@ -411,11 +513,11 @@
#pragma unused(callbackId)
NSString* mediaId = [command.arguments objectAtIndex:0];
- CDVAudioFile* audioFile = [self audioFileForResource:[command.arguments objectAtIndex:1] withId:mediaId];
+ CDVAudioFile* audioFile = [self audioFileForResource:[command.arguments objectAtIndex:1] withId:mediaId doValidation:YES forRecording:YES];
NSString* jsString = nil;
NSString* errorMsg = @"";
- if (audioFile != nil) {
+ if ((audioFile != nil) && (audioFile.resourceURL != nil)) {
NSError* __autoreleasing error = nil;
if (audioFile.recorder != nil) {
@@ -462,9 +564,9 @@
jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]];
}
} else {
- // file does not exist
- NSLog(@"Could not start recording audio, file '%@' does not exist.", audioFile.resourcePath);
- jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:@"File to record to does not exist"]];
+ // file did not validate
+ NSString* errorMsg = [NSString stringWithFormat:@"Could not record audio at '%@'", audioFile.resourcePath];
+ jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]];
}
if (jsString) {
[self.commandDelegate evalJs:jsString];
diff --git a/iPhone/CordovaLib/Classes/CDVSplashScreen.h b/iPhone/CordovaLib/Classes/CDVSplashScreen.h
index b0d8615..a0868a0 100755
--- a/iPhone/CordovaLib/Classes/CDVSplashScreen.h
+++ b/iPhone/CordovaLib/Classes/CDVSplashScreen.h
@@ -20,7 +20,11 @@
#import <Foundation/Foundation.h>
#import "CDVPlugin.h"
-@interface CDVSplashScreen : CDVPlugin {}
+@interface CDVSplashScreen : CDVPlugin {
+ UIActivityIndicatorView* _activityView;
+ UIImageView* _imageView;
+ UIView* _parentView;
+}
- (void)show:(CDVInvokedUrlCommand*)command;
- (void)hide:(CDVInvokedUrlCommand*)command;
diff --git a/iPhone/CordovaLib/Classes/CDVSplashScreen.m b/iPhone/CordovaLib/Classes/CDVSplashScreen.m
index 2512328..cba1b53 100755
--- a/iPhone/CordovaLib/Classes/CDVSplashScreen.m
+++ b/iPhone/CordovaLib/Classes/CDVSplashScreen.m
@@ -18,32 +18,157 @@
*/
#import "CDVSplashScreen.h"
-#import "CDVViewController.h"
+
+#define kSplashScreenStateShow 0
+#define kSplashScreenStateHide 1
+
+#define kSplashScreenDurationDefault 0.25f
@implementation CDVSplashScreen
-- (void)__show:(BOOL)show
+- (void)pluginInitialize
{
- // Legacy support - once deprecated classes removed, clean this up
- id <UIApplicationDelegate> delegate = [[UIApplication sharedApplication] delegate];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
- if ([delegate respondsToSelector:@selector(viewController)]) {
- id vc = [delegate performSelector:@selector(viewController)];
- if ([vc isKindOfClass:[CDVViewController class]]) {
- ((CDVViewController*)vc).imageView.hidden = !show;
- ((CDVViewController*)vc).activityView.hidden = !show;
- }
- }
+ [self show:nil];
}
- (void)show:(CDVInvokedUrlCommand*)command
{
- [self __show:YES];
+ [self updateSplashScreenWithState:kSplashScreenStateShow];
}
- (void)hide:(CDVInvokedUrlCommand*)command
{
- [self __show:NO];
+ [self updateSplashScreenWithState:kSplashScreenStateHide];
+}
+
+- (void)pageDidLoad
+{
+ id autoHideSplashScreenValue = [self.commandDelegate.settings objectForKey:@"AutoHideSplashScreen"];
+
+ // if value is missing, default to yes
+ if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) {
+ [self hide:nil];
+ }
+}
+
+- (void)onOrientationWillChange:(NSNotification*)notification
+{
+ if (_imageView != nil) {
+ UIInterfaceOrientation orientation = [notification.userInfo[UIApplicationStatusBarOrientationUserInfoKey] intValue];
+ [self updateSplashImageForOrientation:orientation];
+ }
+}
+
+- (void)createViews
+{
+ /*
+ * The Activity View is the top spinning throbber in the status/battery bar. We init it with the default Grey Style.
+ *
+ * whiteLarge = UIActivityIndicatorViewStyleWhiteLarge
+ * white = UIActivityIndicatorViewStyleWhite
+ * gray = UIActivityIndicatorViewStyleGray
+ *
+ */
+ NSString* topActivityIndicator = [self.commandDelegate.settings objectForKey:@"TopActivityIndicator"];
+ UIActivityIndicatorViewStyle topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
+
+ if ([topActivityIndicator isEqualToString:@"whiteLarge"]) {
+ topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhiteLarge;
+ } else if ([topActivityIndicator isEqualToString:@"white"]) {
+ topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
+ } else if ([topActivityIndicator isEqualToString:@"gray"]) {
+ topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
+ }
+
+ _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle];
+ _activityView.tag = 2;
+ _activityView.center = self.viewController.view.center;
+ [_activityView startAnimating];
+
+ _imageView = [[UIImageView alloc] init];
+ [self.viewController.view addSubview:_imageView];
+ [self.viewController.view.superview addSubview:_activityView];
+ [self.viewController.view.superview layoutSubviews];
+}
+
+- (void)updateSplashImageForOrientation:(UIInterfaceOrientation)orientation
+{
+ // IPHONE (default)
+ NSString* imageName = @"Default";
+
+ if (CDV_IsIPhone5()) {
+ imageName = [imageName stringByAppendingString:@"-568h"];
+ } else if (CDV_IsIPad()) {
+ // set default to portrait upside down
+ imageName = @"Default-Portrait"; // @"Default-PortraitUpsideDown.png";
+
+ if (orientation == UIInterfaceOrientationLandscapeLeft) {
+ imageName = @"Default-Landscape.png"; // @"Default-LandscapeLeft.png";
+ } else if (orientation == UIInterfaceOrientationLandscapeRight) {
+ imageName = @"Default-Landscape.png"; // @"Default-LandscapeRight.png";
+ }
+ }
+
+ _imageView.image = [UIImage imageNamed:imageName];
+ _imageView.frame = CGRectMake(0, 0, _imageView.image.size.width, _imageView.image.size.height);
+}
+
+- (void)updateSplashScreenWithState:(int)state
+{
+ float toAlpha = state == kSplashScreenStateShow ? 1.0f : 0.0f;
+ BOOL hidden = state == kSplashScreenStateShow ? NO : YES;
+
+ id fadeSplashScreenValue = [self.commandDelegate.settings objectForKey:@"FadeSplashScreen"];
+ id fadeSplashScreenDuration = [self.commandDelegate.settings objectForKey:@"FadeSplashScreenDuration"];
+
+ float fadeDuration = fadeSplashScreenDuration == nil ? kSplashScreenDurationDefault : [fadeSplashScreenDuration floatValue];
+
+ if ((fadeSplashScreenValue == nil) || ![fadeSplashScreenValue boolValue]) {
+ fadeDuration = 0;
+ }
+ if (hidden && (_imageView == nil)) {
+ return;
+ } else if (_imageView == nil) {
+ [self createViews];
+ fadeDuration = 0;
+ }
+
+ if (!hidden) {
+ [self updateSplashImageForOrientation:self.viewController.interfaceOrientation];
+ }
+
+ if (fadeDuration == 0) {
+ [_imageView setHidden:hidden];
+ [_activityView setHidden:hidden];
+ } else {
+ if (state == kSplashScreenStateShow) {
+ // reset states
+ [_imageView setHidden:NO];
+ [_activityView setHidden:NO];
+ [_imageView setAlpha:0.0f];
+ [_activityView setAlpha:0.0f];
+ }
+
+ [UIView transitionWithView:self.viewController.view
+ duration:fadeDuration
+ options:UIViewAnimationOptionTransitionNone
+ animations:^(void) {
+ [_imageView setAlpha:toAlpha];
+ [_activityView setAlpha:toAlpha];
+ }
+ completion:^(BOOL finished) {
+ if (state == kSplashScreenStateHide) {
+ // Clean-up resources.
+ [_imageView removeFromSuperview];
+ [_activityView removeFromSuperview];
+ _imageView = nil;
+ _activityView = nil;
+ }
+ }];
+ }
}
@end
diff --git a/iPhone/CordovaLib/Classes/CDVURLProtocol.h b/iPhone/CordovaLib/Classes/CDVURLProtocol.h
index ce8df38..5444f6d 100755
--- a/iPhone/CordovaLib/Classes/CDVURLProtocol.h
+++ b/iPhone/CordovaLib/Classes/CDVURLProtocol.h
@@ -24,9 +24,6 @@
@interface CDVURLProtocol : NSURLProtocol {}
-+ (void)registerPGHttpURLProtocol CDV_DEPRECATED (2.0, "This is now a no-op and should be removed.");
-+ (void)registerURLProtocol CDV_DEPRECATED (2.0, "This is now a no-op and should be removed.");
-
+ (void)registerViewController:(CDVViewController*)viewController;
+ (void)unregisterViewController:(CDVViewController*)viewController;
@end
diff --git a/iPhone/CordovaLib/Classes/CDVURLProtocol.m b/iPhone/CordovaLib/Classes/CDVURLProtocol.m
index a645288..1959c77 100755
--- a/iPhone/CordovaLib/Classes/CDVURLProtocol.m
+++ b/iPhone/CordovaLib/Classes/CDVURLProtocol.m
@@ -17,14 +17,17 @@
under the License.
*/
+#import <AssetsLibrary/ALAsset.h>
+#import <AssetsLibrary/ALAssetRepresentation.h>
+#import <AssetsLibrary/ALAssetsLibrary.h>
+#import <MobileCoreServices/MobileCoreServices.h>
#import "CDVURLProtocol.h"
#import "CDVCommandQueue.h"
#import "CDVWhitelist.h"
#import "CDVViewController.h"
+#import "CDVFile.h"
@interface CDVHTTPURLResponse : NSHTTPURLResponse
-- (id)initWithUnauthorizedURL:(NSURL*)url;
-- (id)initWithBlankResponse:(NSURL*)url;
@property (nonatomic) NSInteger statusCode;
@end
@@ -106,7 +109,9 @@ static CDVViewController *viewControllerForRequest(NSURLRequest* request)
NSURL* theUrl = [theRequest URL];
CDVViewController* viewController = viewControllerForRequest(theRequest);
- if (viewController != nil) {
+ if ([[theUrl absoluteString] hasPrefix:kCDVAssetsLibraryPrefix]) {
+ return YES;
+ } else if (viewController != nil) {
if ([[theUrl path] isEqualToString:@"/!gap_exec"]) {
NSString* queuedCommandsJSON = [theRequest valueForHTTPHeaderField:@"cmds"];
NSString* requestId = [theRequest valueForHTTPHeaderField:@"rc"];
@@ -151,21 +156,35 @@ static CDVViewController *viewControllerForRequest(NSURLRequest* request)
NSURL* url = [[self request] URL];
if ([[url path] isEqualToString:@"/!gap_exec"]) {
- CDVHTTPURLResponse* response = [[CDVHTTPURLResponse alloc] initWithBlankResponse:url];
- [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
- [[self client] URLProtocolDidFinishLoading:self];
+ [self sendResponseWithResponseCode:200 data:nil mimeType:nil];
+ return;
+ } else if ([[url absoluteString] hasPrefix:kCDVAssetsLibraryPrefix]) {
+ ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+ if (asset) {
+ // We have the asset! Get the data and send it along.
+ ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
+ NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass ((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType);
+ Byte* buffer = (Byte*)malloc ([assetRepresentation size]);
+ NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
+ NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
+ [self sendResponseWithResponseCode:200 data:data mimeType:MIMEType];
+ } else {
+ // Retrieving the asset failed for some reason. Send an error.
+ [self sendResponseWithResponseCode:404 data:nil mimeType:nil];
+ }
+ };
+ ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+ // Retrieving the asset failed for some reason. Send an error.
+ [self sendResponseWithResponseCode:401 data:nil mimeType:nil];
+ };
+
+ ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+ [assetsLibrary assetForURL:url resultBlock:resultBlock failureBlock:failureBlock];
return;
}
NSString* body = [gWhitelist errorStringForURL:url];
-
- CDVHTTPURLResponse* response = [[CDVHTTPURLResponse alloc] initWithUnauthorizedURL:url];
-
- [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
-
- [[self client] URLProtocol:self didLoadData:[body dataUsingEncoding:NSASCIIStringEncoding]];
-
- [[self client] URLProtocolDidFinishLoading:self];
+ [self sendResponseWithResponseCode:401 data:[body dataUsingEncoding:NSASCIIStringEncoding] mimeType:nil];
}
- (void)stopLoading
@@ -178,29 +197,31 @@ static CDVViewController *viewControllerForRequest(NSURLRequest* request)
return NO;
}
-@end
-
-@implementation CDVHTTPURLResponse
-@synthesize statusCode;
-
-- (id)initWithUnauthorizedURL:(NSURL*)url
+- (void)sendResponseWithResponseCode:(NSInteger)statusCode data:(NSData*)data mimeType:(NSString*)mimeType
{
- self = [super initWithURL:url MIMEType:@"text/plain" expectedContentLength:-1 textEncodingName:@"UTF-8"];
- if (self) {
- self.statusCode = 401;
+ if (mimeType == nil) {
+ mimeType = @"text/plain";
}
- return self;
-}
+ NSString* encodingName = [@"text/plain" isEqualToString:mimeType] ? @"UTF-8" : nil;
+ CDVHTTPURLResponse* response =
+ [[CDVHTTPURLResponse alloc] initWithURL:[[self request] URL]
+ MIMEType:mimeType
+ expectedContentLength:[data length]
+ textEncodingName:encodingName];
+ response.statusCode = statusCode;
-- (id)initWithBlankResponse:(NSURL*)url
-{
- self = [super initWithURL:url MIMEType:@"text/plain" expectedContentLength:-1 textEncodingName:@"UTF-8"];
- if (self) {
- self.statusCode = 200;
+ [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+ if (data != nil) {
+ [[self client] URLProtocol:self didLoadData:data];
}
- return self;
+ [[self client] URLProtocolDidFinishLoading:self];
}
+@end
+
+@implementation CDVHTTPURLResponse
+@synthesize statusCode;
+
- (NSDictionary*)allHeaderFields
{
return nil;
diff --git a/iPhone/CordovaLib/Classes/CDVCordovaView.m b/iPhone/CordovaLib/Classes/CDVUserAgentUtil.h
index 3dff80a..4de382f 100755
--- a/iPhone/CordovaLib/Classes/CDVCordovaView.m
+++ b/iPhone/CordovaLib/Classes/CDVUserAgentUtil.h
@@ -17,21 +17,11 @@
under the License.
*/
-#import "CDVCordovaView.h"
-
-@implementation CDVCordovaView
-
-- (void)loadRequest:(NSURLRequest*)request
-{
- [super loadRequest:request];
-}
-
-/*
-// Only override drawRect: if you perform custom drawing.
-// An empty implementation adversely affects performance during animation.
-- (void)drawRect:(CGRect)rect {
- // Drawing code.
-}
-*/
+#import <Foundation/Foundation.h>
+@interface CDVUserAgentUtil : NSObject
++ (NSString*)originalUserAgent;
++ (void)acquireLock:(void (^)(NSInteger lockToken))block;
++ (void)releaseLock:(NSInteger*)lockToken;
++ (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken;
@end
diff --git a/iPhone/CordovaLib/Classes/CDVUserAgentUtil.m b/iPhone/CordovaLib/Classes/CDVUserAgentUtil.m
new file mode 100755
index 0000000..5c43c51
--- /dev/null
+++ b/iPhone/CordovaLib/Classes/CDVUserAgentUtil.m
@@ -0,0 +1,120 @@
+/*
+ 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 "CDVUserAgentUtil.h"
+
+#import <UIKit/UIKit.h>
+
+// #define VerboseLog NSLog
+#define VerboseLog(...) do {} while (0)
+
+static NSString* const kCdvUserAgentKey = @"Cordova-User-Agent";
+static NSString* const kCdvUserAgentVersionKey = @"Cordova-User-Agent-Version";
+
+static NSString* gOriginalUserAgent = nil;
+static NSInteger gNextLockToken = 0;
+static NSInteger gCurrentLockToken = 0;
+static NSMutableArray* gPendingSetUserAgentBlocks = nil;
+
+@implementation CDVUserAgentUtil
+
++ (NSString*)originalUserAgent
+{
+ if (gOriginalUserAgent == nil) {
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppLocaleDidChange:)
+ name:NSCurrentLocaleDidChangeNotification object:nil];
+
+ NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
+ NSString* systemVersion = [[UIDevice currentDevice] systemVersion];
+ NSString* localeStr = [[NSLocale currentLocale] localeIdentifier];
+ NSString* systemAndLocale = [NSString stringWithFormat:@"%@ %@", systemVersion, localeStr];
+
+ NSString* cordovaUserAgentVersion = [userDefaults stringForKey:kCdvUserAgentVersionKey];
+ gOriginalUserAgent = [userDefaults stringForKey:kCdvUserAgentKey];
+ BOOL cachedValueIsOld = ![systemAndLocale isEqualToString:cordovaUserAgentVersion];
+
+ if ((gOriginalUserAgent == nil) || cachedValueIsOld) {
+ UIWebView* sampleWebView = [[UIWebView alloc] initWithFrame:CGRectZero];
+ gOriginalUserAgent = [sampleWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
+
+ [userDefaults setObject:gOriginalUserAgent forKey:kCdvUserAgentKey];
+ [userDefaults setObject:systemAndLocale forKey:kCdvUserAgentVersionKey];
+
+ [userDefaults synchronize];
+ }
+ }
+ return gOriginalUserAgent;
+}
+
++ (void)onAppLocaleDidChange:(NSNotification*)notification
+{
+ // TODO: We should figure out how to update the user-agent of existing UIWebViews when this happens.
+ // Maybe use the PDF bug (noted in setUserAgent:).
+ gOriginalUserAgent = nil;
+}
+
++ (void)acquireLock:(void (^)(NSInteger lockToken))block
+{
+ if (gCurrentLockToken == 0) {
+ gCurrentLockToken = ++gNextLockToken;
+ VerboseLog(@"Gave lock %d", gCurrentLockToken);
+ block(gCurrentLockToken);
+ } else {
+ if (gPendingSetUserAgentBlocks == nil) {
+ gPendingSetUserAgentBlocks = [[NSMutableArray alloc] initWithCapacity:4];
+ }
+ VerboseLog(@"Waiting for lock");
+ [gPendingSetUserAgentBlocks addObject:block];
+ }
+}
+
++ (void)releaseLock:(NSInteger*)lockToken
+{
+ if (*lockToken == 0) {
+ return;
+ }
+ NSAssert(gCurrentLockToken == *lockToken, @"Got token %d, expected %d", *lockToken, gCurrentLockToken);
+
+ VerboseLog(@"Released lock %d", *lockToken);
+ if ([gPendingSetUserAgentBlocks count] > 0) {
+ void (^block)() = [gPendingSetUserAgentBlocks objectAtIndex:0];
+ [gPendingSetUserAgentBlocks removeObjectAtIndex:0];
+ gCurrentLockToken = ++gNextLockToken;
+ NSLog (@"Gave lock %d", gCurrentLockToken);
+ block(gCurrentLockToken);
+ } else {
+ gCurrentLockToken = 0;
+ }
+ *lockToken = 0;
+}
+
++ (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken
+{
+ NSAssert(gCurrentLockToken == lockToken, @"Got token %d, expected %d", lockToken, gCurrentLockToken);
+ VerboseLog(@"User-Agent set to: %@", value);
+
+ // Setting the UserAgent must occur before a UIWebView is instantiated.
+ // It is read per instantiation, so it does not affect previously created views.
+ // Except! When a PDF is loaded, all currently active UIWebViews reload their
+ // User-Agent from the NSUserDefaults some time after the DidFinishLoad of the PDF bah!
+ NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:value, @"UserAgent", nil];
+ [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
+}
+
+@end
diff --git a/iPhone/CordovaLib/Classes/CDVViewController.h b/iPhone/CordovaLib/Classes/CDVViewController.h
index 8318398..82e22f6 100755
--- a/iPhone/CordovaLib/Classes/CDVViewController.h
+++ b/iPhone/CordovaLib/Classes/CDVViewController.h
@@ -17,9 +17,8 @@
under the License.
*/
-#import "CDVCordovaView.h"
-
-#import "JSONKit.h"
+#import <UIKit/UIKit.h>
+#import <Foundation/NSJSONSerialization.h>
#import "CDVAvailability.h"
#import "CDVInvokedUrlCommand.h"
#import "CDVCommandDelegate.h"
@@ -37,19 +36,15 @@
NSString* _userAgent;
}
-@property (nonatomic, strong) IBOutlet CDVCordovaView* webView;
+@property (nonatomic, strong) IBOutlet UIWebView* webView;
@property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects;
@property (nonatomic, readonly, strong) NSDictionary* pluginsMap;
-@property (nonatomic, readonly, strong) NSDictionary* settings;
+@property (nonatomic, readonly, strong) NSMutableDictionary* settings;
@property (nonatomic, readonly, strong) NSXMLParser* configParser;
@property (nonatomic, readonly, strong) CDVWhitelist* whitelist; // readonly for public
@property (nonatomic, readonly, assign) BOOL loadFromString;
-@property (nonatomic, readwrite, copy)NSString * invokeString CDV_DEPRECATED(2.0, "Use window.handleOpenURL(url instead. It is called when the app is launched through a custom scheme url.");
-
-@property (nonatomic, readwrite, assign) BOOL useSplashScreen;
-@property (nonatomic, readonly, strong) IBOutlet UIActivityIndicatorView* activityView;
-@property (nonatomic, readonly, strong) UIImageView* imageView;
+@property (nonatomic, readwrite, assign) BOOL useSplashScreen CDV_DEPRECATED(2.5, "Add/Remove the SplashScreen plugin instead of setting this property.");
@property (nonatomic, readwrite, copy) NSString* wwwFolderName;
@property (nonatomic, readwrite, copy) NSString* startPage;
@@ -59,11 +54,10 @@
+ (NSDictionary*)getBundlePlist:(NSString*)plistName;
+ (NSString*)applicationDocumentsDirectory;
-+ (NSString*)originalUserAgent;
- (void)printMultitaskingInfo;
- (void)createGapView;
-- (CDVCordovaView*)newCordovaViewWithFrame:(CGRect)bounds;
+- (UIWebView*)newCordovaViewWithFrame:(CGRect)bounds;
- (void)javascriptAlert:(NSString*)text;
- (NSString*)appURLScheme;
diff --git a/iPhone/CordovaLib/Classes/CDVViewController.m b/iPhone/CordovaLib/Classes/CDVViewController.m
index f1b36df..bec716d 100755
--- a/iPhone/CordovaLib/Classes/CDVViewController.m
+++ b/iPhone/CordovaLib/Classes/CDVViewController.m
@@ -22,36 +22,38 @@
#import "CDVCommandQueue.h"
#import "CDVCommandDelegateImpl.h"
#import "CDVConfigParser.h"
+#import "CDVUserAgentUtil.h"
+#import "CDVWebViewDelegate.h"
#define degreesToRadian(x) (M_PI * (x) / 180.0)
-#define CDV_USER_AGENT_KEY @"Cordova-User-Agent"
-#define CDV_USER_AGENT_VERSION_KEY @"Cordova-User-Agent-Version"
-static NSString* gOriginalUserAgent = nil;
-
-@interface CDVViewController ()
+@interface CDVViewController () {
+ NSInteger _userAgentLockToken;
+ CDVWebViewDelegate* _webViewDelegate;
+}
@property (nonatomic, readwrite, strong) NSXMLParser* configParser;
-@property (nonatomic, readwrite, strong) NSDictionary* settings;
+@property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
@property (nonatomic, readwrite, strong) CDVWhitelist* whitelist;
@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects;
+@property (nonatomic, readwrite, strong) NSArray* startupPluginNames;
@property (nonatomic, readwrite, strong) NSDictionary* pluginsMap;
@property (nonatomic, readwrite, strong) NSArray* supportedOrientations;
@property (nonatomic, readwrite, assign) BOOL loadFromString;
-@property (nonatomic, readwrite, strong) IBOutlet UIActivityIndicatorView* activityView;
-@property (nonatomic, readwrite, strong) UIImageView* imageView;
@property (readwrite, assign) BOOL initialized;
+@property (atomic, strong) NSURL* openURL;
+
@end
@implementation CDVViewController
@synthesize webView, supportedOrientations;
-@synthesize pluginObjects, pluginsMap, whitelist;
+@synthesize pluginObjects, pluginsMap, whitelist, startupPluginNames;
@synthesize configParser, settings, loadFromString;
-@synthesize imageView, activityView, useSplashScreen;
-@synthesize wwwFolderName, startPage, invokeString, initialized;
+@synthesize useSplashScreen;
+@synthesize wwwFolderName, startPage, initialized, openURL;
@synthesize commandDelegate = _commandDelegate;
@synthesize commandQueue = _commandQueue;
@@ -60,38 +62,30 @@ static NSString* gOriginalUserAgent = nil;
if ((self != nil) && !self.initialized) {
_commandQueue = [[CDVCommandQueue alloc] initWithViewController:self];
_commandDelegate = [[CDVCommandDelegateImpl alloc] initWithViewController:self];
- [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedOrientationChange)
- name:UIDeviceOrientationDidChangeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillTerminate:)
name:UIApplicationWillTerminateNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillResignActive:)
name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppLocaleDidChange:)
- name:NSCurrentLocaleDidChangeNotification object:nil];
-
- if (IsAtLeastiOSVersion(@"4.0")) {
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillEnterForeground:)
- name:UIApplicationWillEnterForegroundNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground:)
- name:UIApplicationDidEnterBackgroundNotification object:nil];
- }
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillEnterForeground:)
+ name:UIApplicationWillEnterForegroundNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground:)
+ name:UIApplicationDidEnterBackgroundNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOpenURL:) name:CDVPluginHandleOpenURLNotification object:nil];
// read from UISupportedInterfaceOrientations (or UISupportedInterfaceOrientations~iPad, if its iPad) from -Info.plist
self.supportedOrientations = [self parseInterfaceOrientations:
[[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"]];
- self.wwwFolderName = @"www";
- self.startPage = @"index.html";
-
[self printMultitaskingInfo];
[self printDeprecationNotice];
self.initialized = YES;
// load config.xml settings
[self loadSettings];
+ useSplashScreen = YES;
}
}
@@ -167,12 +161,20 @@ static NSString* gOriginalUserAgent = nil;
[configParser parse];
// Get the plugin dictionary, whitelist and settings from the delegate.
- self.pluginsMap = [delegate.pluginsDict dictionaryWithLowercaseKeys];
+ self.pluginsMap = delegate.pluginsDict;
+ self.startupPluginNames = delegate.startupPluginNames;
self.whitelist = [[CDVWhitelist alloc] initWithArray:delegate.whitelistHosts];
self.settings = delegate.settings;
+ // And the start folder/page.
+ self.wwwFolderName = @"www";
+ self.startPage = delegate.startPage;
+ if (self.startPage == nil) {
+ self.startPage = @"index.html";
+ }
+
// Initialize the plugin objects dict.
- self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:4];
+ self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:20];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
@@ -203,13 +205,14 @@ static NSString* gOriginalUserAgent = nil;
NSString* backupWebStorageType = @"cloud"; // default value
- id backupWebStorage = [self.settings objectForKey:@"BackupWebStorage"];
+ id backupWebStorage = self.settings[@"BackupWebStorage"];
if ([backupWebStorage isKindOfClass:[NSString class]]) {
backupWebStorageType = backupWebStorage;
} else if ([backupWebStorage isKindOfClass:[NSNumber class]]) {
NSLog(@"Deprecated: BackupWebStorage boolean property is a string property now (none, local, cloud). A boolean value of 'true' will be mapped to 'cloud'. Consult the docs: http://docs.cordova.io/en/edge/guide_project-settings_ios_index.md.html#Project%%20Settings%%20for%%20iOS");
backupWebStorageType = [(NSNumber*) backupWebStorage boolValue] ? @"cloud" : @"none";
}
+ self.settings[@"BackupWebStorage"] = backupWebStorageType;
if (IsAtLeastiOSVersion(@"5.1")) {
[CDVLocalStorage __fixupDatabaseLocationsWithBackupType:backupWebStorageType];
@@ -244,8 +247,7 @@ static NSString* gOriginalUserAgent = nil;
*/
if (IsAtLeastiOSVersion(@"5.1") && (([backupWebStorageType isEqualToString:@"local"]) ||
([backupWebStorageType isEqualToString:@"cloud"] && !IsAtLeastiOSVersion(@"6.0")))) {
- [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView settings:[NSDictionary dictionaryWithObjectsAndKeys:
- @"backupType", backupWebStorageType, nil]] withClassName:NSStringFromClass([CDVLocalStorage class])];
+ [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView] withClassName:NSStringFromClass([CDVLocalStorage class])];
}
/*
@@ -305,15 +307,27 @@ static NSString* gOriginalUserAgent = nil;
}
}
- // /////////////////
+ for (NSString* pluginName in self.startupPluginNames) {
+ [self getCommandInstance:pluginName];
+ }
- if (!loadErr) {
- NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
- [self.webView loadRequest:appReq];
- } else {
- NSString* html = [NSString stringWithFormat:@"<html><body> %@ </body></html>", loadErr];
- [self.webView loadHTMLString:html baseURL:nil];
+ // TODO: Remove this explicit instantiation once we move to cordova-CLI.
+ if (useSplashScreen) {
+ [self getCommandInstance:@"splashscreen"];
}
+
+ // /////////////////
+ [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
+ _userAgentLockToken = lockToken;
+ [CDVUserAgentUtil setUserAgent:self.userAgent lockToken:lockToken];
+ if (!loadErr) {
+ NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
+ [self.webView loadRequest:appReq];
+ } else {
+ NSString* html = [NSString stringWithFormat:@"<html><body> %@ </body></html>", loadErr];
+ [self.webView loadHTMLString:html baseURL:nil];
+ }
+ }];
}
- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations
@@ -411,55 +425,15 @@ static NSString* gOriginalUserAgent = nil;
return [self.supportedOrientations containsObject:[NSNumber numberWithInt:orientation]];
}
-/**
- Called by UIKit when the device starts to rotate to a new orientation. This fires the \c setOrientation
- method on the Orientation object in JavaScript. Look at the JavaScript documentation for more information.
- */
-- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
-{
- if (!IsAtLeastiOSVersion(@"5.0")) {
- NSString* jsCallback = [NSString stringWithFormat:
- @"window.__defineGetter__('orientation',function(){ return %d; }); \
- cordova.fireWindowEvent('orientationchange');"
- , [self mapIosOrientationToJsOrientation:fromInterfaceOrientation]];
- [self.commandDelegate evalJs:jsCallback];
- }
-}
-
-- (CDVCordovaView*)newCordovaViewWithFrame:(CGRect)bounds
-{
- return [[CDVCordovaView alloc] initWithFrame:bounds];
-}
-
-+ (NSString*)originalUserAgent
+- (UIWebView*)newCordovaViewWithFrame:(CGRect)bounds
{
- if (gOriginalUserAgent == nil) {
- NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
- NSString* systemVersion = [[UIDevice currentDevice] systemVersion];
- NSString* localeStr = [[NSLocale currentLocale] localeIdentifier];
- NSString* systemAndLocale = [NSString stringWithFormat:@"%@ %@", systemVersion, localeStr];
-
- NSString* cordovaUserAgentVersion = [userDefaults stringForKey:CDV_USER_AGENT_VERSION_KEY];
- gOriginalUserAgent = [userDefaults stringForKey:CDV_USER_AGENT_KEY];
- BOOL cachedValueIsOld = ![systemAndLocale isEqualToString:cordovaUserAgentVersion];
-
- if ((gOriginalUserAgent == nil) || cachedValueIsOld) {
- UIWebView* sampleWebView = [[UIWebView alloc] initWithFrame:CGRectZero];
- gOriginalUserAgent = [sampleWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
-
- [userDefaults setObject:gOriginalUserAgent forKey:CDV_USER_AGENT_KEY];
- [userDefaults setObject:systemAndLocale forKey:CDV_USER_AGENT_VERSION_KEY];
-
- [userDefaults synchronize];
- }
- }
- return gOriginalUserAgent;
+ return [[UIWebView alloc] initWithFrame:bounds];
}
- (NSString*)userAgent
{
if (_userAgent == nil) {
- NSString* originalUserAgent = [[self class] originalUserAgent];
+ NSString* originalUserAgent = [CDVUserAgentUtil originalUserAgent];
// Use our address as a unique number to append to the User-Agent.
_userAgent = [NSString stringWithFormat:@"%@ (%lld)", originalUserAgent, (long long)self];
}
@@ -473,18 +447,14 @@ static NSString* gOriginalUserAgent = nil;
webViewBounds.origin = self.view.bounds.origin;
if (!self.webView) {
- // setting the UserAgent must occur before the UIWebView is instantiated.
- // This is read per instantiation, so it does not affect the main Cordova UIWebView
- NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:self.userAgent, @"UserAgent", nil];
- [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
-
self.webView = [self newCordovaViewWithFrame:webViewBounds];
self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
[self.view addSubview:self.webView];
[self.view sendSubviewToBack:self.webView];
- self.webView.delegate = self;
+ _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self];
+ self.webView.delegate = _webViewDelegate;
// register this viewcontroller with the NSURLProtocol, only after the User-Agent is set
[CDVURLProtocol registerViewController:self];
@@ -523,6 +493,7 @@ static NSString* gOriginalUserAgent = nil;
self.webView.delegate = nil;
self.webView = nil;
+ [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
}
#pragma mark UIWebViewDelegate
@@ -533,43 +504,41 @@ static NSString* gOriginalUserAgent = nil;
*/
- (void)webViewDidStartLoad:(UIWebView*)theWebView
{
+ NSLog(@"Resetting plugins due to page load.");
[_commandQueue resetRequestId];
- [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:nil]];
+ [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:self.webView]];
}
/**
- Called when the webview finishes loading. This stops the activity view and closes the imageview
+ Called when the webview finishes loading. This stops the activity view.
*/
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
+ NSLog(@"Finished load of: %@", theWebView.request.URL);
+ // It's safe to release the lock even if this is just a sub-frame that's finished loading.
+ [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
+
+ // The .onNativeReady().fire() will work when cordova.js is already loaded.
+ // The _nativeReady = true; is used when this is run before cordova.js is loaded.
+ NSString* nativeReady = @"try{cordova.require('cordova/channel').onNativeReady.fire();}catch(e){window._nativeReady = true;}";
+ // Don't use [commandDelegate evalJs] here since it relies on cordova.js being loaded already.
+ [self.webView stringByEvaluatingJavaScriptFromString:nativeReady];
+
/*
* Hide the Top Activity THROBBER in the Battery Bar
*/
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
- id autoHideSplashScreenValue = [self.settings objectForKey:@"AutoHideSplashScreen"];
- // if value is missing, default to yes
- if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) {
- self.imageView.hidden = YES;
- self.activityView.hidden = YES;
- [self.view.superview bringSubviewToFront:self.webView];
- }
- [self didRotateFromInterfaceOrientation:(UIInterfaceOrientation)[[UIDevice currentDevice] orientation]];
+ [self processOpenUrl];
- // The .onNativeReady().fire() will work when cordova.js is already loaded.
- // The _nativeReady = true; is used when this is run before cordova.js is loaded.
- NSString* nativeReady = @"try{cordova.require('cordova/channel').onNativeReady.fire();}catch(e){window._nativeReady = true;}";
- [self.commandDelegate evalJs:nativeReady];
+ [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:nil]];
}
-- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
+- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
{
- NSLog(@"Failed to load webpage with error: %@", [error localizedDescription]);
+ [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
- /*
- if ([error code] != NSURLErrorCancelled)
- alert([error localizedDescription]);
- */
+ NSLog(@"Failed to load webpage with error: %@", [error localizedDescription]);
}
- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
@@ -625,8 +594,6 @@ static NSString* gOriginalUserAgent = nil;
* Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview.
*/
else {
- // BOOL isIFrame = ([theWebView.request.mainDocumentURL absoluteString] == nil);
-
if ([self.whitelist schemeIsAllowed:[url scheme]]) {
return [self.whitelist URLIsAllowed:url];
} else {
@@ -677,131 +644,6 @@ static NSString* gOriginalUserAgent = nil;
return basePath;
}
-- (void)showSplashScreen
-{
- CGRect screenBounds = [[UIScreen mainScreen] bounds];
- NSString* launchImageFile = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchImageFile"];
-
- if (launchImageFile == nil) { // fallback if no launch image was specified
- if (CDV_IsIPhone5()) {
- // iPhone 5 or iPod Touch 6th-gen
- launchImageFile = @"Default-568h";
- } else {
- launchImageFile = @"Default";
- }
- }
-
- NSString* orientedLaunchImageFile = nil;
- CGAffineTransform startupImageTransform = CGAffineTransformIdentity;
- UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
- CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
- UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
- UIImage* launchImage = nil;
-
- // default to center of screen as in the original implementation. This will produce the 20px jump
- CGPoint center = CGPointMake((screenBounds.size.width / 2), (screenBounds.size.height / 2));
-
- if (CDV_IsIPad()) {
- if (!UIDeviceOrientationIsValidInterfaceOrientation(deviceOrientation)) {
- deviceOrientation = (UIDeviceOrientation)statusBarOrientation;
- }
-
- switch (deviceOrientation) {
- case UIDeviceOrientationLandscapeLeft: // this is where the home button is on the right (yeah, I know, confusing)
- {
- orientedLaunchImageFile = [NSString stringWithFormat:@"%@-Landscape", launchImageFile];
- startupImageTransform = CGAffineTransformMakeRotation(degreesToRadian(90));
- center.x -= MIN(statusBarFrame.size.width, statusBarFrame.size.height) / 2;
- }
- break;
-
- case UIDeviceOrientationLandscapeRight: // this is where the home button is on the left (yeah, I know, confusing)
- {
- orientedLaunchImageFile = [NSString stringWithFormat:@"%@-Landscape", launchImageFile];
- startupImageTransform = CGAffineTransformMakeRotation(degreesToRadian(-90));
- center.x += MIN(statusBarFrame.size.width, statusBarFrame.size.height) / 2;
- }
- break;
-
- case UIDeviceOrientationPortraitUpsideDown:
- {
- orientedLaunchImageFile = [NSString stringWithFormat:@"%@-Portrait", launchImageFile];
- startupImageTransform = CGAffineTransformMakeRotation(degreesToRadian(180));
- center.y -= MIN(statusBarFrame.size.width, statusBarFrame.size.height) / 2;
- }
- break;
-
- case UIDeviceOrientationPortrait:
- default:
- {
- orientedLaunchImageFile = [NSString stringWithFormat:@"%@-Portrait", launchImageFile];
- startupImageTransform = CGAffineTransformIdentity;
- center.y += MIN(statusBarFrame.size.width, statusBarFrame.size.height) / 2;
- }
- break;
- }
- } else { // not iPad
- orientedLaunchImageFile = launchImageFile;
- }
-
- launchImage = [UIImage imageNamed:[[self class] resolveImageResource:orientedLaunchImageFile]];
- if (launchImage == nil) {
- NSLog(@"WARNING: Splash-screen image '%@' was not found. Orientation: %d, iPad: %d", orientedLaunchImageFile, deviceOrientation, CDV_IsIPad());
- }
-
- self.imageView = [[UIImageView alloc] initWithImage:launchImage];
- self.imageView.tag = 1;
- self.imageView.center = center;
-
- self.imageView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin);
- [self.imageView setTransform:startupImageTransform];
- [self.view.superview addSubview:self.imageView];
-
- /*
- * The Activity View is the top spinning throbber in the status/battery bar. We init it with the default Grey Style.
- *
- * whiteLarge = UIActivityIndicatorViewStyleWhiteLarge
- * white = UIActivityIndicatorViewStyleWhite
- * gray = UIActivityIndicatorViewStyleGray
- *
- */
- NSString* topActivityIndicator = [self.settings objectForKey:@"TopActivityIndicator"];
- UIActivityIndicatorViewStyle topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
-
- if ([topActivityIndicator isEqualToString:@"whiteLarge"]) {
- topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhiteLarge;
- } else if ([topActivityIndicator isEqualToString:@"white"]) {
- topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
- } else if ([topActivityIndicator isEqualToString:@"gray"]) {
- topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
- }
-
- self.activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle];
- self.activityView.tag = 2;
-
- id showSplashScreenSpinnerValue = [self.settings objectForKey:@"ShowSplashScreenSpinner"];
- // backwards compatibility - if key is missing, default to true
- if ((showSplashScreenSpinnerValue == nil) || [showSplashScreenSpinnerValue boolValue]) {
- [self.view.superview addSubview:self.activityView];
- }
-
- self.activityView.center = self.view.center;
- [self.activityView startAnimating];
-
- [self.view.superview layoutSubviews];
-}
-
-BOOL gSplashScreenShown = NO;
-- (void)receivedOrientationChange
-{
- if (self.imageView == nil) {
- gSplashScreenShown = YES;
- if (self.useSplashScreen) {
- [self showSplashScreen];
- }
- }
-}
-
#pragma mark CordovaCommands
- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className
@@ -815,6 +657,7 @@ BOOL gSplashScreenShown = NO;
}
[self.pluginObjects setObject:plugin forKey:className];
+ [plugin pluginInitialize];
}
/**
@@ -835,16 +678,9 @@ BOOL gSplashScreenShown = NO;
id obj = [self.pluginObjects objectForKey:className];
if (!obj) {
- // attempt to load the settings for this command class
- NSDictionary* classSettings = [self.settings objectForKey:className];
-
- if (classSettings) {
- obj = [[NSClassFromString (className)alloc] initWithWebView:webView settings:classSettings];
- } else {
- obj = [[NSClassFromString (className)alloc] initWithWebView:webView];
- }
+ obj = [[NSClassFromString (className)alloc] initWithWebView:webView];
- if ((obj != nil) && [obj isKindOfClass:[CDVPlugin class]]) {
+ if (obj != nil) {
[self registerPlugin:obj withClassName:className];
} else {
NSLog(@"CDVPlugin class %@ (pluginName: %@) does not exist.", className, pluginName);
@@ -956,9 +792,21 @@ BOOL gSplashScreenShown = NO;
[self.commandDelegate evalJs:@"cordova.fireDocumentEvent('pause', null, true);" scheduledOnRunLoop:NO];
}
-- (void)onAppLocaleDidChange:(NSNotification*)notification
+// ///////////////////////
+
+- (void)handleOpenURL:(NSNotification*)notification
+{
+ self.openURL = notification.object;
+}
+
+- (void)processOpenUrl
{
- gOriginalUserAgent = nil;
+ if (self.openURL) {
+ // calls into javascript global function 'handleOpenURL'
+ NSString* jsString = [NSString stringWithFormat:@"handleOpenURL(\"%@\");", [self.openURL description]];
+ [self.webView stringByEvaluatingJavaScriptFromString:jsString];
+ self.openURL = nil;
+ }
}
// ///////////////////////
@@ -972,9 +820,10 @@ BOOL gSplashScreenShown = NO;
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil];
-
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:CDVPluginHandleOpenURLNotification object:nil];
self.webView.delegate = nil;
self.webView = nil;
+ [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
[_commandQueue dispose];
[[self.pluginObjects allValues] makeObjectsPerformSelector:@selector(dispose)];
}
diff --git a/iPhone/CordovaLib/Classes/CDVWebViewDelegate.h b/iPhone/CordovaLib/Classes/CDVWebViewDelegate.h
new file mode 100755
index 0000000..8a89a22
--- /dev/null
+++ b/iPhone/CordovaLib/Classes/CDVWebViewDelegate.h
@@ -0,0 +1,37 @@
+/*
+ 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 <UIKit/UIKit.h>
+
+/**
+ * Distinguishes top-level navigations from sub-frame navigations.
+ * shouldStartLoadWithRequest is called for every request, but didStartLoad
+ * and didFinishLoad is called only for top-level navigations.
+ * Relevant bug: CB-2389
+ */
+@interface CDVWebViewDelegate : NSObject <UIWebViewDelegate>{
+ __weak NSObject <UIWebViewDelegate>* _delegate;
+ NSInteger _loadCount;
+ NSInteger _state;
+ NSInteger _curLoadToken;
+}
+
+- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate;
+
+@end
diff --git a/iPhone/CordovaLib/Classes/CDVWebViewDelegate.m b/iPhone/CordovaLib/Classes/CDVWebViewDelegate.m
new file mode 100755
index 0000000..9ee8186
--- /dev/null
+++ b/iPhone/CordovaLib/Classes/CDVWebViewDelegate.m
@@ -0,0 +1,157 @@
+/*
+ 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 "CDVWebViewDelegate.h"
+#import "CDVAvailability.h"
+
+typedef enum {
+ STATE_NORMAL,
+ STATE_SHOULD_LOAD_MISSING,
+ STATE_WAITING_FOR_START,
+ STATE_WAITING_FOR_FINISH
+} State;
+
+@implementation CDVWebViewDelegate
+
+- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate
+{
+ self = [super init];
+ if (self != nil) {
+ _delegate = delegate;
+ _loadCount = -1;
+ _state = STATE_NORMAL;
+ }
+ return self;
+}
+
+- (BOOL)isPageLoaded:(UIWebView*)webView
+{
+ NSString* readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];
+
+ return [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"];
+}
+
+- (BOOL)isJsLoadTokenSet:(UIWebView*)webView
+{
+ NSString* loadToken = [webView stringByEvaluatingJavaScriptFromString:@"window.__cordovaLoadToken"];
+
+ return [[NSString stringWithFormat:@"%d", _curLoadToken] isEqualToString:loadToken];
+}
+
+- (void)setLoadToken:(UIWebView*)webView
+{
+ _curLoadToken += 1;
+ [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.__cordovaLoadToken=%d", _curLoadToken]];
+}
+
+- (void)pollForPageLoadStart:(UIWebView*)webView
+{
+ if ((_state != STATE_WAITING_FOR_START) && (_state != STATE_SHOULD_LOAD_MISSING)) {
+ return;
+ }
+ if (![self isJsLoadTokenSet:webView]) {
+ _state = STATE_WAITING_FOR_FINISH;
+ [self setLoadToken:webView];
+ [_delegate webViewDidStartLoad:webView];
+ [self pollForPageLoadFinish:webView];
+ }
+}
+
+- (void)pollForPageLoadFinish:(UIWebView*)webView
+{
+ if (_state != STATE_WAITING_FOR_FINISH) {
+ return;
+ }
+ if ([self isPageLoaded:webView]) {
+ _state = STATE_SHOULD_LOAD_MISSING;
+ [_delegate webViewDidFinishLoad:webView];
+ } else {
+ [self performSelector:@selector(pollForPageLoaded) withObject:webView afterDelay:50];
+ }
+}
+
+- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
+{
+ BOOL shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
+
+ if (shouldLoad) {
+ BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]];
+ if (isTopLevelNavigation) {
+ _loadCount = 0;
+ _state = STATE_NORMAL;
+ }
+ }
+ return shouldLoad;
+}
+
+- (void)webViewDidStartLoad:(UIWebView*)webView
+{
+ if (_state == STATE_NORMAL) {
+ if (_loadCount == 0) {
+ [_delegate webViewDidStartLoad:webView];
+ _loadCount += 1;
+ } else if (_loadCount > 0) {
+ _loadCount += 1;
+ } else if (!IsAtLeastiOSVersion(@"6.0")) {
+ // If history.go(-1) is used pre-iOS6, the shouldStartLoadWithRequest function is not called.
+ // Without shouldLoad, we can't distinguish an iframe from a top-level navigation.
+ // We could try to distinguish using [UIWebView canGoForward], but that's too much complexity,
+ // and would work only on the first time it was used.
+
+ // Our work-around is to set a JS variable and poll until it disappears (from a naviagtion).
+ _state = STATE_WAITING_FOR_START;
+ [self setLoadToken:webView];
+ }
+ } else {
+ [self pollForPageLoadStart:webView];
+ [self pollForPageLoadFinish:webView];
+ }
+}
+
+- (void)webViewDidFinishLoad:(UIWebView*)webView
+{
+ if (_state == STATE_NORMAL) {
+ if (_loadCount == 1) {
+ [_delegate webViewDidFinishLoad:webView];
+ _loadCount -= 1;
+ } else if (_loadCount > 1) {
+ _loadCount -= 1;
+ }
+ } else {
+ [self pollForPageLoadStart:webView];
+ [self pollForPageLoadFinish:webView];
+ }
+}
+
+- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
+{
+ if (_state == STATE_NORMAL) {
+ if (_loadCount == 1) {
+ [_delegate webView:webView didFailLoadWithError:error];
+ _loadCount -= 1;
+ } else if (_loadCount > 1) {
+ _loadCount -= 1;
+ }
+ } else {
+ [self pollForPageLoadStart:webView];
+ [self pollForPageLoadFinish:webView];
+ }
+}
+
+@end
diff --git a/iPhone/CordovaLib/Classes/JSON/JSONKit.h b/iPhone/CordovaLib/Classes/JSON/JSONKit.h
deleted file mode 100755
index 2b245cd..0000000
--- a/iPhone/CordovaLib/Classes/JSON/JSONKit.h
+++ /dev/null
@@ -1,251 +0,0 @@
-//
-// JSONKit.h
-// http://github.com/johnezang/JSONKit
-// Dual licensed under either the terms of the BSD License, or alternatively
-// under the terms of the Apache License, Version 2.0, as specified below.
-//
-
-/*
- Copyright (c) 2011, John Engelhart
-
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the Zang Industries nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-/*
- Copyright 2011 John Engelhart
-
- Licensed 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.
-*/
-
-#include <stddef.h>
-#include <stdint.h>
-#include <limits.h>
-#include <TargetConditionals.h>
-#include <AvailabilityMacros.h>
-
-#ifdef __OBJC__
-#import <Foundation/NSArray.h>
-#import <Foundation/NSData.h>
-#import <Foundation/NSDictionary.h>
-#import <Foundation/NSError.h>
-#import <Foundation/NSObjCRuntime.h>
-#import <Foundation/NSString.h>
-#endif // __OBJC__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-// For Mac OS X < 10.5.
-#ifndef NSINTEGER_DEFINED
-#define NSINTEGER_DEFINED
-#if defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
-typedef long NSInteger;
-typedef unsigned long NSUInteger;
-#define NSIntegerMin LONG_MIN
-#define NSIntegerMax LONG_MAX
-#define NSUIntegerMax ULONG_MAX
-#else // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
-typedef int NSInteger;
-typedef unsigned int NSUInteger;
-#define NSIntegerMin INT_MIN
-#define NSIntegerMax INT_MAX
-#define NSUIntegerMax UINT_MAX
-#endif // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
-#endif // NSINTEGER_DEFINED
-
-
-#ifndef _CDVJSONKIT_H_
-#define _CDVJSONKIT_H_
-
-#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__APPLE_CC__) && (__APPLE_CC__ >= 5465)
-#define CDVJK_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
-#else
-#define CDVJK_DEPRECATED_ATTRIBUTE
-#endif
-
-#define CDVJSONKIT_VERSION_MAJOR 1
-#define CDVJSONKIT_VERSION_MINOR 4
-
-typedef NSUInteger CDVJKFlags;
-
-/*
- CDVJKParseOptionComments : Allow C style // and /_* ... *_/ (without a _, obviously) comments in JSON.
- CDVJKParseOptionUnicodeNewlines : Allow Unicode recommended (?:\r\n|[\n\v\f\r\x85\p{Zl}\p{Zp}]) newlines.
- CDVJKParseOptionLooseUnicode : Normally the decoder will stop with an error at any malformed Unicode.
- This option allows JSON with malformed Unicode to be parsed without reporting an error.
- Any malformed Unicode is replaced with \uFFFD, or "REPLACEMENT CHARACTER".
- */
-
-enum {
- CDVJKParseOptionNone = 0,
- CDVJKParseOptionStrict = 0,
- CDVJKParseOptionComments = (1 << 0),
- CDVJKParseOptionUnicodeNewlines = (1 << 1),
- CDVJKParseOptionLooseUnicode = (1 << 2),
- CDVJKParseOptionPermitTextAfterValidJSON = (1 << 3),
- CDVJKParseOptionValidFlags = (CDVJKParseOptionComments | CDVJKParseOptionUnicodeNewlines | CDVJKParseOptionLooseUnicode | CDVJKParseOptionPermitTextAfterValidJSON),
-};
-typedef CDVJKFlags CDVJKParseOptionFlags;
-
-enum {
- CDVJKSerializeOptionNone = 0,
- CDVJKSerializeOptionPretty = (1 << 0),
- CDVJKSerializeOptionEscapeUnicode = (1 << 1),
- CDVJKSerializeOptionEscapeForwardSlashes = (1 << 4),
- CDVJKSerializeOptionValidFlags = (CDVJKSerializeOptionPretty | CDVJKSerializeOptionEscapeUnicode | CDVJKSerializeOptionEscapeForwardSlashes),
-};
-typedef CDVJKFlags CDVJKSerializeOptionFlags;
-
-#ifdef __OBJC__
-
-typedef struct CDVJKParseState CDVJKParseState; // Opaque internal, private type.
-
-// As a general rule of thumb, if you use a method that doesn't accept a CDVJKParseOptionFlags argument, it defaults to CDVJKParseOptionStrict
-
-@interface CDVJSONDecoder : NSObject {
- CDVJKParseState *parseState;
-}
-+ (id)decoder;
-+ (id)decoderWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags;
-- (id)initWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags;
-- (void)clearCache;
-
-// The parse... methods were deprecated in v1.4 in favor of the v1.4 objectWith... methods.
-- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length CDVJK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithUTF8String:length: instead.
-- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length error:(NSError **)error CDVJK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithUTF8String:length:error: instead.
-// The NSData MUST be UTF8 encoded JSON.
-- (id)parseJSONData:(NSData *)jsonData CDVJK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithData: instead.
-- (id)parseJSONData:(NSData *)jsonData error:(NSError **)error CDVJK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithData:error: instead.
-
-// Methods that return immutable collection objects.
-- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length;
-- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error;
-// The NSData MUST be UTF8 encoded JSON.
-- (id)objectWithData:(NSData *)jsonData;
-- (id)objectWithData:(NSData *)jsonData error:(NSError **)error;
-
-// Methods that return mutable collection objects.
-- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length;
-- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error;
-// The NSData MUST be UTF8 encoded JSON.
-- (id)mutableObjectWithData:(NSData *)jsonData;
-- (id)mutableObjectWithData:(NSData *)jsonData error:(NSError **)error;
-
-@end
-
-////////////
-#pragma mark Deserializing methods
-////////////
-
-@interface NSString (CDVJSONKitDeserializing)
-- (id)cdvjk_objectFromJSONString;
-- (id)cdvjk_objectFromJSONStringWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags;
-- (id)cdvjk_objectFromJSONStringWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags error:(NSError **)error;
-- (id)cdvjk_mutableObjectFromJSONString;
-- (id)cdvjk_mutableObjectFromJSONStringWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags;
-- (id)cdvjk_mutableObjectFromJSONStringWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags error:(NSError **)error;
-@end
-
-@interface NSData (CDVJSONKitDeserializing)
-// The NSData MUST be UTF8 encoded JSON.
-- (id)cdvjk_objectFromJSONData;
-- (id)cdvjk_objectFromJSONDataWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags;
-- (id)cdvjk_objectFromJSONDataWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags error:(NSError **)error;
-- (id)cdvjk_mutableObjectFromJSONData;
-- (id)cdvjk_mutableObjectFromJSONDataWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags;
-- (id)cdvjk_mutableObjectFromJSONDataWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags error:(NSError **)error;
-@end
-
-////////////
-#pragma mark Serializing methods
-////////////
-
-@interface NSString (CDVJSONKitSerializing)
-// Convenience methods for those that need to serialize the receiving NSString (i.e., instead of having to serialize a NSArray with a single NSString, you can "serialize to JSON" just the NSString).
-// Normally, a string that is serialized to JSON has quotation marks surrounding it, which you may or may not want when serializing a single string, and can be controlled with includeQuotes:
-// includeQuotes:YES `a "test"...` -> `"a \"test\"..."`
-// includeQuotes:NO `a "test"...` -> `a \"test\"...`
-- (NSData *)cdvjk_JSONData; // Invokes JSONDataWithOptions:CDVJKSerializeOptionNone includeQuotes:YES
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error;
-- (NSString *)cdvjk_JSONString; // Invokes JSONStringWithOptions:CDVJKSerializeOptionNone includeQuotes:YES
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error;
-@end
-
-@interface NSArray (CDVJSONKitSerializing)
-- (NSData *)cdvjk_JSONData;
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions error:(NSError **)error;
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
-- (NSString *)cdvjk_JSONString;
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions error:(NSError **)error;
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
-@end
-
-@interface NSDictionary (CDVJSONKitSerializing)
-- (NSData *)cdvjk_JSONData;
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions error:(NSError **)error;
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
-- (NSString *)cdvjk_JSONString;
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions error:(NSError **)error;
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
-@end
-
-#ifdef __BLOCKS__
-
-@interface NSArray (CDVJSONKitSerializingBlockAdditions)
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
-@end
-
-@interface NSDictionary (CDVJSONKitSerializingBlockAdditions)
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
-@end
-
-#endif
-
-
-#endif // __OBJC__
-
-#endif // _CDVJSONKIT_H_
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
diff --git a/iPhone/CordovaLib/Classes/JSON/JSONKit.m b/iPhone/CordovaLib/Classes/JSON/JSONKit.m
deleted file mode 100755
index 15a7171..0000000
--- a/iPhone/CordovaLib/Classes/JSON/JSONKit.m
+++ /dev/null
@@ -1,3061 +0,0 @@
-//
-// JSONKit.m
-// http://github.com/johnezang/JSONKit
-// Dual licensed under either the terms of the BSD License, or alternatively
-// under the terms of the Apache License, Version 2.0, as specified below.
-//
-
-/*
- Copyright (c) 2011, John Engelhart
-
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the Zang Industries nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-/*
- Copyright 2011 John Engelhart
-
- Licensed 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.
-*/
-
-
-/*
- Acknowledgments:
-
- The bulk of the UTF8 / UTF32 conversion and verification comes
- from ConvertUTF.[hc]. It has been modified from the original sources.
-
- The original sources were obtained from http://www.unicode.org/.
- However, the web site no longer seems to host the files. Instead,
- the Unicode FAQ http://www.unicode.org/faq//utf_bom.html#gen4
- points to International Components for Unicode (ICU)
- http://site.icu-project.org/ as an example of how to write a UTF
- converter.
-
- The decision to use the ConvertUTF.[ch] code was made to leverage
- "proven" code. Hopefully the local modifications are bug free.
-
- The code in isValidCodePoint() is derived from the ICU code in
- utf.h for the macros U_IS_UNICODE_NONCHAR and U_IS_UNICODE_CHAR.
-
- From the original ConvertUTF.[ch]:
-
- * Copyright 2001-2004 Unicode, Inc.
- *
- * Disclaimer
- *
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
- *
- * Limitations on Rights to Redistribute This Code
- *
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
-
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <assert.h>
-#include <sys/errno.h>
-#include <math.h>
-#include <limits.h>
-#include <objc/runtime.h>
-
-#import "JSONKit.h"
-
-//#include <CoreFoundation/CoreFoundation.h>
-#include <CoreFoundation/CFString.h>
-#include <CoreFoundation/CFArray.h>
-#include <CoreFoundation/CFDictionary.h>
-#include <CoreFoundation/CFNumber.h>
-
-//#import <Foundation/Foundation.h>
-#import <Foundation/NSArray.h>
-#import <Foundation/NSAutoreleasePool.h>
-#import <Foundation/NSData.h>
-#import <Foundation/NSDictionary.h>
-#import <Foundation/NSException.h>
-#import <Foundation/NSNull.h>
-#import <Foundation/NSObjCRuntime.h>
-
-#ifndef __cdv_has_feature
-#define __cdv_has_feature(x) 0
-#endif
-
-#ifdef CDVJK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS
-#warning As of CDVJSONKit v1.4, CDVJK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS is no longer required. It is no longer a valid option.
-#endif
-
-#ifdef __OBJC_GC__
-#error CDVJSONKit does not support Objective-C Garbage Collection
-#endif
-
-#if __has_feature(objc_arc)
-#error CDVJSONKit does not support Objective-C Automatic Reference Counting (ARC)
-#endif
-
-// The following checks are really nothing more than sanity checks.
-// CDVJSONKit technically has a few problems from a "strictly C99 conforming" standpoint, though they are of the pedantic nitpicking variety.
-// In practice, though, for the compilers and architectures we can reasonably expect this code to be compiled for, these pedantic nitpicks aren't really a problem.
-// Since we're limited as to what we can do with pre-processor #if checks, these checks are not nearly as through as they should be.
-
-#if (UINT_MAX != 0xffffffffU) || (INT_MIN != (-0x7fffffff-1)) || (ULLONG_MAX != 0xffffffffffffffffULL) || (LLONG_MIN != (-0x7fffffffffffffffLL-1LL))
-#error CDVJSONKit requires the C 'int' and 'long long' types to be 32 and 64 bits respectively.
-#endif
-
-#if !defined(__LP64__) && ((UINT_MAX != ULONG_MAX) || (INT_MAX != LONG_MAX) || (INT_MIN != LONG_MIN) || (WORD_BIT != LONG_BIT))
-#error CDVJSONKit requires the C 'int' and 'long' types to be the same on 32-bit architectures.
-#endif
-
-// Cocoa / Foundation uses NS*Integer as the type for a lot of arguments. We make sure that NS*Integer is something we are expecting and is reasonably compatible with size_t / ssize_t
-
-#if (NSUIntegerMax != ULONG_MAX) || (NSIntegerMax != LONG_MAX) || (NSIntegerMin != LONG_MIN)
-#error CDVJSONKit requires NSInteger and NSUInteger to be the same size as the C 'long' type.
-#endif
-
-#if (NSUIntegerMax != SIZE_MAX) || (NSIntegerMax != SSIZE_MAX)
-#error CDVJSONKit requires NSInteger and NSUInteger to be the same size as the C 'size_t' type.
-#endif
-
-
-// For DJB hash.
-#define CDVJK_HASH_INIT (1402737925UL)
-
-// Use __builtin_clz() instead of trailingBytesForUTF8[] table lookup.
-#define CDVJK_FAST_TRAILING_BYTES
-
-// CDVJK_CACHE_SLOTS must be a power of 2. Default size is 1024 slots.
-#define CDVJK_CACHE_SLOTS_BITS (10)
-#define CDVJK_CACHE_SLOTS (1UL << CDVJK_CACHE_SLOTS_BITS)
-// CDVJK_CACHE_PROBES is the number of probe attempts.
-#define CDVJK_CACHE_PROBES (4UL)
-// CDVJK_INIT_CACHE_AGE must be (1 << AGE) - 1
-#define CDVJK_INIT_CACHE_AGE (0)
-
-// CDVJK_TOKENBUFFER_SIZE is the default stack size for the temporary buffer used to hold "non-simple" strings (i.e., contains \ escapes)
-#define CDVJK_TOKENBUFFER_SIZE (1024UL * 2UL)
-
-// CDVJK_STACK_OBJS is the default number of spaces reserved on the stack for temporarily storing pointers to Obj-C objects before they can be transferred to a NSArray / NSDictionary.
-#define CDVJK_STACK_OBJS (1024UL * 1UL)
-
-#define CDVJK_JSONBUFFER_SIZE (1024UL * 4UL)
-#define CDVJK_UTF8BUFFER_SIZE (1024UL * 16UL)
-
-#define CDVJK_ENCODE_CACHE_SLOTS (1024UL)
-
-
-#if defined (__GNUC__) && (__GNUC__ >= 4)
-#define CDVJK_ATTRIBUTES(attr, ...) __attribute__((attr, ##__VA_ARGS__))
-#define CDVJK_EXPECTED(cond, expect) __builtin_expect((long)(cond), (expect))
-#define CDVJK_EXPECT_T(cond) CDVJK_EXPECTED(cond, 1U)
-#define CDVJK_EXPECT_F(cond) CDVJK_EXPECTED(cond, 0U)
-#define CDVJK_PREFETCH(ptr) __builtin_prefetch(ptr)
-#else // defined (__GNUC__) && (__GNUC__ >= 4)
-#define CDVJK_ATTRIBUTES(attr, ...)
-#define CDVJK_EXPECTED(cond, expect) (cond)
-#define CDVJK_EXPECT_T(cond) (cond)
-#define CDVJK_EXPECT_F(cond) (cond)
-#define CDVJK_PREFETCH(ptr)
-#endif // defined (__GNUC__) && (__GNUC__ >= 4)
-
-#define CDVJK_STATIC_INLINE static __inline__ CDVJK_ATTRIBUTES(always_inline)
-#define CDVJK_ALIGNED(arg) CDVJK_ATTRIBUTES(aligned(arg))
-#define CDVJK_UNUSED_ARG CDVJK_ATTRIBUTES(unused)
-#define CDVJK_WARN_UNUSED CDVJK_ATTRIBUTES(warn_unused_result)
-#define CDVJK_WARN_UNUSED_CONST CDVJK_ATTRIBUTES(warn_unused_result, const)
-#define CDVJK_WARN_UNUSED_PURE CDVJK_ATTRIBUTES(warn_unused_result, pure)
-#define CDVJK_WARN_UNUSED_SENTINEL CDVJK_ATTRIBUTES(warn_unused_result, sentinel)
-#define CDVJK_NONNULL_ARGS(arg, ...) CDVJK_ATTRIBUTES(nonnull(arg, ##__VA_ARGS__))
-#define CDVJK_WARN_UNUSED_NONNULL_ARGS(arg, ...) CDVJK_ATTRIBUTES(warn_unused_result, nonnull(arg, ##__VA_ARGS__))
-#define CDVJK_WARN_UNUSED_CONST_NONNULL_ARGS(arg, ...) CDVJK_ATTRIBUTES(warn_unused_result, const, nonnull(arg, ##__VA_ARGS__))
-#define CDVJK_WARN_UNUSED_PURE_NONNULL_ARGS(arg, ...) CDVJK_ATTRIBUTES(warn_unused_result, pure, nonnull(arg, ##__VA_ARGS__))
-
-#if defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
-#define CDVJK_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(as, nn, ...) CDVJK_ATTRIBUTES(warn_unused_result, nonnull(nn, ##__VA_ARGS__), alloc_size(as))
-#else // defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
-#define CDVJK_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(as, nn, ...) CDVJK_ATTRIBUTES(warn_unused_result, nonnull(nn, ##__VA_ARGS__))
-#endif // defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
-
-
-@class CDVJKArray, CDVJKDictionaryEnumerator, CDVJKDictionary;
-
-enum {
- CDVJSONNumberStateStart = 0,
- CDVJSONNumberStateFinished = 1,
- CDVJSONNumberStateError = 2,
- CDVJSONNumberStateWholeNumberStart = 3,
- CDVJSONNumberStateWholeNumberMinus = 4,
- CDVJSONNumberStateWholeNumberZero = 5,
- CDVJSONNumberStateWholeNumber = 6,
- CDVJSONNumberStatePeriod = 7,
- CDVJSONNumberStateFractionalNumberStart = 8,
- CDVJSONNumberStateFractionalNumber = 9,
- CDVJSONNumberStateExponentStart = 10,
- CDVJSONNumberStateExponentPlusMinus = 11,
- CDVJSONNumberStateExponent = 12,
-};
-
-enum {
- CDVJSONStringStateStart = 0,
- CDVJSONStringStateParsing = 1,
- CDVJSONStringStateFinished = 2,
- CDVJSONStringStateError = 3,
- CDVJSONStringStateEscape = 4,
- CDVJSONStringStateEscapedUnicode1 = 5,
- CDVJSONStringStateEscapedUnicode2 = 6,
- CDVJSONStringStateEscapedUnicode3 = 7,
- CDVJSONStringStateEscapedUnicode4 = 8,
- CDVJSONStringStateEscapedUnicodeSurrogate1 = 9,
- CDVJSONStringStateEscapedUnicodeSurrogate2 = 10,
- CDVJSONStringStateEscapedUnicodeSurrogate3 = 11,
- CDVJSONStringStateEscapedUnicodeSurrogate4 = 12,
- CDVJSONStringStateEscapedNeedEscapeForSurrogate = 13,
- CDVJSONStringStateEscapedNeedEscapedUForSurrogate = 14,
-};
-
-enum {
- CDVJKParseAcceptValue = (1 << 0),
- CDVJKParseAcceptComma = (1 << 1),
- CDVJKParseAcceptEnd = (1 << 2),
- CDVJKParseAcceptValueOrEnd = (CDVJKParseAcceptValue | CDVJKParseAcceptEnd),
- CDVJKParseAcceptCommaOrEnd = (CDVJKParseAcceptComma | CDVJKParseAcceptEnd),
-};
-
-enum {
- CDVJKClassUnknown = 0,
- CDVJKClassString = 1,
- CDVJKClassNumber = 2,
- CDVJKClassArray = 3,
- CDVJKClassDictionary = 4,
- CDVJKClassNull = 5,
-};
-
-enum {
- CDVJKManagedBufferOnStack = 1,
- CDVJKManagedBufferOnHeap = 2,
- CDVJKManagedBufferLocationMask = (0x3),
- CDVJKManagedBufferLocationShift = (0),
-
- CDVJKManagedBufferMustFree = (1 << 2),
-};
-typedef CDVJKFlags CDVJKManagedBufferFlags;
-
-enum {
- CDVJKObjectStackOnStack = 1,
- CDVJKObjectStackOnHeap = 2,
- CDVJKObjectStackLocationMask = (0x3),
- CDVJKObjectStackLocationShift = (0),
-
- CDVJKObjectStackMustFree = (1 << 2),
-};
-typedef CDVJKFlags CDVJKObjectStackFlags;
-
-enum {
- CDVJKTokenTypeInvalid = 0,
- CDVJKTokenTypeNumber = 1,
- CDVJKTokenTypeString = 2,
- CDVJKTokenTypeObjectBegin = 3,
- CDVJKTokenTypeObjectEnd = 4,
- CDVJKTokenTypeArrayBegin = 5,
- CDVJKTokenTypeArrayEnd = 6,
- CDVJKTokenTypeSeparator = 7,
- CDVJKTokenTypeComma = 8,
- CDVJKTokenTypeTrue = 9,
- CDVJKTokenTypeFalse = 10,
- CDVJKTokenTypeNull = 11,
- CDVJKTokenTypeWhiteSpace = 12,
-};
-typedef NSUInteger CDVJKTokenType;
-
-// These are prime numbers to assist with hash slot probing.
-enum {
- CDVJKValueTypeNone = 0,
- CDVJKValueTypeString = 5,
- CDVJKValueTypeLongLong = 7,
- CDVJKValueTypeUnsignedLongLong = 11,
- CDVJKValueTypeDouble = 13,
-};
-typedef NSUInteger CDVJKValueType;
-
-enum {
- CDVJKEncodeOptionAsData = 1,
- CDVJKEncodeOptionAsString = 2,
- CDVJKEncodeOptionAsTypeMask = 0x7,
- CDVJKEncodeOptionCollectionObj = (1 << 3),
- CDVJKEncodeOptionStringObj = (1 << 4),
- CDVJKEncodeOptionStringObjTrimQuotes = (1 << 5),
-
-};
-typedef NSUInteger CDVJKEncodeOptionType;
-
-typedef NSUInteger CDVJKHash;
-
-typedef struct CDVJKTokenCacheItem CDVJKTokenCacheItem;
-typedef struct CDVJKTokenCache CDVJKTokenCache;
-typedef struct CDVJKTokenValue CDVJKTokenValue;
-typedef struct CDVJKParseToken CDVJKParseToken;
-typedef struct CDVJKPtrRange CDVJKPtrRange;
-typedef struct CDVJKObjectStack CDVJKObjectStack;
-typedef struct CDVJKBuffer CDVJKBuffer;
-typedef struct CDVJKConstBuffer CDVJKConstBuffer;
-typedef struct CDVJKConstPtrRange CDVJKConstPtrRange;
-typedef struct CDVJKRange CDVJKRange;
-typedef struct CDVJKManagedBuffer CDVJKManagedBuffer;
-typedef struct CDVJKFastClassLookup CDVJKFastClassLookup;
-typedef struct CDVJKEncodeCache CDVJKEncodeCache;
-typedef struct CDVJKEncodeState CDVJKEncodeState;
-typedef struct CDVJKObjCImpCache CDVJKObjCImpCache;
-typedef struct CDVJKHashTableEntry CDVJKHashTableEntry;
-
-typedef id (*NSNumberAllocImp)(id receiver, SEL selector);
-typedef id (*NSNumberInitWithUnsignedLongLongImp)(id receiver, SEL selector, unsigned long long value);
-typedef id (*CDVJKClassFormatterIMP)(id receiver, SEL selector, id object);
-#ifdef __BLOCKS__
-typedef id (^CDVJKClassFormatterBlock)(id formatObject);
-#endif
-
-
-struct CDVJKPtrRange {
- unsigned char *ptr;
- size_t length;
-};
-
-struct CDVJKConstPtrRange {
- const unsigned char *ptr;
- size_t length;
-};
-
-struct CDVJKRange {
- size_t location, length;
-};
-
-struct CDVJKManagedBuffer {
- CDVJKPtrRange bytes;
- CDVJKManagedBufferFlags flags;
- size_t roundSizeUpToMultipleOf;
-};
-
-struct CDVJKObjectStack {
- void **objects, **keys;
- CFHashCode *cfHashes;
- size_t count, index, roundSizeUpToMultipleOf;
- CDVJKObjectStackFlags flags;
-};
-
-struct CDVJKBuffer {
- CDVJKPtrRange bytes;
-};
-
-struct CDVJKConstBuffer {
- CDVJKConstPtrRange bytes;
-};
-
-struct CDVJKTokenValue {
- CDVJKConstPtrRange ptrRange;
- CDVJKValueType type;
- CDVJKHash hash;
- union {
- long long longLongValue;
- unsigned long long unsignedLongLongValue;
- double doubleValue;
- } number;
- CDVJKTokenCacheItem *cacheItem;
-};
-
-struct CDVJKParseToken {
- CDVJKConstPtrRange tokenPtrRange;
- CDVJKTokenType type;
- CDVJKTokenValue value;
- CDVJKManagedBuffer tokenBuffer;
-};
-
-struct CDVJKTokenCacheItem {
- void *object;
- CDVJKHash hash;
- CFHashCode cfHash;
- size_t size;
- unsigned char *bytes;
- CDVJKValueType type;
-};
-
-struct CDVJKTokenCache {
- CDVJKTokenCacheItem *items;
- size_t count;
- unsigned int prng_lfsr;
- unsigned char age[CDVJK_CACHE_SLOTS];
-};
-
-struct CDVJKObjCImpCache {
- Class NSNumberClass;
- NSNumberAllocImp NSNumberAlloc;
- NSNumberInitWithUnsignedLongLongImp NSNumberInitWithUnsignedLongLong;
-};
-
-struct CDVJKParseState {
- CDVJKParseOptionFlags parseOptionFlags;
- CDVJKConstBuffer stringBuffer;
- size_t atIndex, lineNumber, lineStartIndex;
- size_t prev_atIndex, prev_lineNumber, prev_lineStartIndex;
- CDVJKParseToken token;
- CDVJKObjectStack objectStack;
- CDVJKTokenCache cache;
- CDVJKObjCImpCache objCImpCache;
- NSError *error;
- int errorIsPrev;
- BOOL mutableCollections;
-};
-
-struct CDVJKFastClassLookup {
- void *stringClass;
- void *numberClass;
- void *arrayClass;
- void *dictionaryClass;
- void *nullClass;
-};
-
-struct CDVJKEncodeCache {
- id object;
- size_t offset;
- size_t length;
-};
-
-struct CDVJKEncodeState {
- CDVJKManagedBuffer utf8ConversionBuffer;
- CDVJKManagedBuffer stringBuffer;
- size_t atIndex;
- CDVJKFastClassLookup fastClassLookup;
- CDVJKEncodeCache cache[CDVJK_ENCODE_CACHE_SLOTS];
- CDVJKSerializeOptionFlags serializeOptionFlags;
- CDVJKEncodeOptionType encodeOption;
- size_t depth;
- NSError *error;
- id classFormatterDelegate;
- SEL classFormatterSelector;
- CDVJKClassFormatterIMP classFormatterIMP;
-#ifdef __BLOCKS__
- CDVJKClassFormatterBlock classFormatterBlock;
-#endif
-};
-
-// This is a CDVJSONKit private class.
-@interface CDVJKSerializer : NSObject {
- CDVJKEncodeState *encodeState;
-}
-
-#ifdef __BLOCKS__
-#define CDVJKSERIALIZER_BLOCKS_PROTO id(^)(id object)
-#else
-#define CDVJKSERIALIZER_BLOCKS_PROTO id
-#endif
-
-+ (id)serializeObject:(id)object options:(CDVJKSerializeOptionFlags)optionFlags encodeOption:(CDVJKEncodeOptionType)encodeOption block:(CDVJKSERIALIZER_BLOCKS_PROTO)block delegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
-- (id)serializeObject:(id)object options:(CDVJKSerializeOptionFlags)optionFlags encodeOption:(CDVJKEncodeOptionType)encodeOption block:(CDVJKSERIALIZER_BLOCKS_PROTO)block delegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
-- (void)releaseState;
-
-@end
-
-struct CDVJKHashTableEntry {
- NSUInteger keyHash;
- id key, object;
-};
-
-
-typedef uint32_t UTF32; /* at least 32 bits */
-typedef uint16_t UTF16; /* at least 16 bits */
-typedef uint8_t UTF8; /* typically 8 bits */
-
-typedef enum {
- conversionOK, /* conversion successful */
- sourceExhausted, /* partial character in source, but hit end */
- targetExhausted, /* insuff. room in target for conversion */
- sourceIllegal /* source sequence is illegal/malformed */
-} CDV_ConversionResult;
-
-#define CDV_UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
-#define CDV_UNI_MAX_BMP (UTF32)0x0000FFFF
-#define CDV_UNI_MAX_UTF16 (UTF32)0x0010FFFF
-#define CDV_UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
-#define CDV_UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
-#define CDV_UNI_SUR_HIGH_START (UTF32)0xD800
-#define CDV_UNI_SUR_HIGH_END (UTF32)0xDBFF
-#define CDV_UNI_SUR_LOW_START (UTF32)0xDC00
-#define CDV_UNI_SUR_LOW_END (UTF32)0xDFFF
-
-
-#if !defined(CDVJK_FAST_TRAILING_BYTES)
-static const char trailingBytesForUTF8[256] = {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
-};
-#endif
-
-static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
-static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
-
-#define CDVJK_AT_STRING_PTR(x) (&((x)->stringBuffer.bytes.ptr[(x)->atIndex]))
-#define CDVJK_END_STRING_PTR(x) (&((x)->stringBuffer.bytes.ptr[(x)->stringBuffer.bytes.length]))
-
-
-static CDVJKArray *_CDVJKArrayCreate(id *objects, NSUInteger count, BOOL mutableCollection);
-static void _CDVJKArrayInsertObjectAtIndex(CDVJKArray *array, id newObject, NSUInteger objectIndex);
-static void _CDVJKArrayReplaceObjectAtIndexWithObject(CDVJKArray *array, NSUInteger objectIndex, id newObject);
-static void _CDVJKArrayRemoveObjectAtIndex(CDVJKArray *array, NSUInteger objectIndex);
-
-
-static NSUInteger _CDVJKDictionaryCapacityForCount(NSUInteger count);
-static CDVJKDictionary *_CDVJKDictionaryCreate(id *keys, NSUInteger *keyHashes, id *objects, NSUInteger count, BOOL mutableCollection);
-static CDVJKHashTableEntry *_CDVJKDictionaryHashEntry(CDVJKDictionary *dictionary);
-static NSUInteger _CDVJKDictionaryCapacity(CDVJKDictionary *dictionary);
-static void _CDVJKDictionaryResizeIfNeccessary(CDVJKDictionary *dictionary);
-static void _CDVJKDictionaryRemoveObjectWithEntry(CDVJKDictionary *dictionary, CDVJKHashTableEntry *entry);
-static void _CDVJKDictionaryAddObject(CDVJKDictionary *dictionary, NSUInteger keyHash, id key, id object);
-static CDVJKHashTableEntry *_CDVJKDictionaryHashTableEntryForKey(CDVJKDictionary *dictionary, id aKey);
-
-
-static void _CDVJSONDecoderCleanup(CDVJSONDecoder *decoder);
-
-static id _CDVNSStringObjectFromJSONString(NSString *jsonString, CDVJKParseOptionFlags parseOptionFlags, NSError **error, BOOL mutableCollection);
-
-
-static void cdvjk_managedBuffer_release(CDVJKManagedBuffer *managedBuffer);
-static void cdvjk_managedBuffer_setToStackBuffer(CDVJKManagedBuffer *managedBuffer, unsigned char *ptr, size_t length);
-static unsigned char *cdvjk_managedBuffer_resize(CDVJKManagedBuffer *managedBuffer, size_t newSize);
-static void cdvjk_objectStack_release(CDVJKObjectStack *objectStack);
-static void cdvjk_objectStack_setToStackBuffer(CDVJKObjectStack *objectStack, void **objects, void **keys, CFHashCode *cfHashes, size_t count);
-static int cdvjk_objectStack_resize(CDVJKObjectStack *objectStack, size_t newCount);
-
-static void cdvjk_error(CDVJKParseState *parseState, NSString *format, ...);
-static int cdvjk_parse_string(CDVJKParseState *parseState);
-static int cdvjk_parse_number(CDVJKParseState *parseState);
-static size_t cdvjk_parse_is_newline(CDVJKParseState *parseState, const unsigned char *atCharacterPtr);
-CDVJK_STATIC_INLINE int cdvjk_parse_skip_newline(CDVJKParseState *parseState);
-CDVJK_STATIC_INLINE void cdvjk_parse_skip_whitespace(CDVJKParseState *parseState);
-static int cdvjk_parse_next_token(CDVJKParseState *parseState);
-static void cdvjk_error_parse_accept_or3(CDVJKParseState *parseState, int state, NSString *or1String, NSString *or2String, NSString *or3String);
-static void *cdvjk_create_dictionary(CDVJKParseState *parseState, size_t startingObjectIndex);
-static void *cdvjk_parse_dictionary(CDVJKParseState *parseState);
-static void *cdvjk_parse_array(CDVJKParseState *parseState);
-static void *cdvjk_object_for_token(CDVJKParseState *parseState);
-static void *cdvjk_cachedObjects(CDVJKParseState *parseState);
-CDVJK_STATIC_INLINE void cdvjk_cache_age(CDVJKParseState *parseState);
-CDVJK_STATIC_INLINE void cdvjk_set_parsed_token(CDVJKParseState *parseState, const unsigned char *ptr, size_t length, CDVJKTokenType type, size_t advanceBy);
-
-
-static void cdvjk_encode_error(CDVJKEncodeState *encodeState, NSString *format, ...);
-static int cdvjk_encode_printf(CDVJKEncodeState *encodeState, CDVJKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format, ...);
-static int cdvjk_encode_write(CDVJKEncodeState *encodeState, CDVJKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format);
-static int cdvjk_encode_writePrettyPrintWhiteSpace(CDVJKEncodeState *encodeState);
-static int cdvjk_encode_write1slow(CDVJKEncodeState *encodeState, ssize_t depthChange, const char *format);
-static int cdvjk_encode_write1fast(CDVJKEncodeState *encodeState, ssize_t depthChange CDVJK_UNUSED_ARG, const char *format);
-static int cdvjk_encode_writen(CDVJKEncodeState *encodeState, CDVJKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format, size_t length);
-CDVJK_STATIC_INLINE CDVJKHash cdvjk_encode_object_hash(void *objectPtr);
-CDVJK_STATIC_INLINE void cdvjk_encode_updateCache(CDVJKEncodeState *encodeState, CDVJKEncodeCache *cacheSlot, size_t startingAtIndex, id object);
-static int cdvjk_encode_add_atom_to_buffer(CDVJKEncodeState *encodeState, void *objectPtr);
-
-#define cdvjk_encode_write1(es, dc, f) (CDVJK_EXPECT_F(_jk_encode_prettyPrint) ? cdvjk_encode_write1slow(es, dc, f) : cdvjk_encode_write1fast(es, dc, f))
-
-
-CDVJK_STATIC_INLINE size_t cdvjk_min(size_t a, size_t b);
-CDVJK_STATIC_INLINE size_t cdvjk_max(size_t a, size_t b);
-CDVJK_STATIC_INLINE CDVJKHash cdvcalculateHash(CDVJKHash currentHash, unsigned char c);
-
-// CDVJSONKit v1.4 used both a CDVJKArray : NSArray and CDVJKMutableArray : NSMutableArray, and the same for the dictionary collection type.
-// However, Louis Gerbarg (via cocoa-dev) pointed out that Cocoa / Core Foundation actually implements only a single class that inherits from the
-// mutable version, and keeps an ivar bit for whether or not that instance is mutable. This means that the immutable versions of the collection
-// classes receive the mutating methods, but this is handled by having those methods throw an exception when the ivar bit is set to immutable.
-// We adopt the same strategy here. It's both cleaner and gets rid of the method swizzling hackery used in CDVJSONKit v1.4.
-
-
-// This is a workaround for issue #23 https://github.com/johnezang/JSONKit/pull/23
-// Basically, there seem to be a problem with using +load in static libraries on iOS. However, __attribute__ ((constructor)) does work correctly.
-// Since we do not require anything "special" that +load provides, and we can accomplish the same thing using __attribute__ ((constructor)), the +load logic was moved here.
-
-static Class _CDVJKArrayClass = NULL;
-static size_t _CDVJKArrayInstanceSize = 0UL;
-static Class _CDVJKDictionaryClass = NULL;
-static size_t _CDVJKDictionaryInstanceSize = 0UL;
-
-// For CDVJSONDecoder...
-static Class _CDVjk_NSNumberClass = NULL;
-static NSNumberAllocImp _CDVjk_NSNumberAllocImp = NULL;
-static NSNumberInitWithUnsignedLongLongImp _CDVjk_NSNumberInitWithUnsignedLongLongImp = NULL;
-
-extern void cdvjk_collectionClassLoadTimeInitialization(void) __attribute__ ((constructor));
-
-void cdvjk_collectionClassLoadTimeInitialization(void) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Though technically not required, the run time environment at load time initialization may be less than ideal.
-
- _CDVJKArrayClass = objc_getClass("CDVJKArray");
- _CDVJKArrayInstanceSize = cdvjk_max(16UL, class_getInstanceSize(_CDVJKArrayClass));
-
- _CDVJKDictionaryClass = objc_getClass("CDVJKDictionary");
- _CDVJKDictionaryInstanceSize = cdvjk_max(16UL, class_getInstanceSize(_CDVJKDictionaryClass));
-
- // For CDVJSONDecoder...
- _CDVjk_NSNumberClass = [NSNumber class];
- _CDVjk_NSNumberAllocImp = (NSNumberAllocImp)[NSNumber methodForSelector:@selector(alloc)];
-
- // Hacktacular. Need to do it this way due to the nature of class clusters.
- id temp_NSNumber = [NSNumber alloc];
- _CDVjk_NSNumberInitWithUnsignedLongLongImp = (NSNumberInitWithUnsignedLongLongImp)[temp_NSNumber methodForSelector:@selector(initWithUnsignedLongLong:)];
- [[temp_NSNumber init] release];
- temp_NSNumber = NULL;
-
- [pool release]; pool = NULL;
-}
-
-
-#pragma mark -
-@interface CDVJKArray : NSMutableArray <NSCopying, NSMutableCopying, NSFastEnumeration> {
- id *objects;
- NSUInteger count, capacity, mutations;
-}
-@end
-
-@implementation CDVJKArray
-
-+ (id)allocWithZone:(NSZone *)zone
-{
-#pragma unused(zone)
- [NSException raise:NSInvalidArgumentException format:@"*** - [%@ %@]: The %@ class is private to CDVJSONKit and should not be used in this fashion.", NSStringFromClass([self class]), NSStringFromSelector(_cmd), NSStringFromClass([self class])];
- return(NULL);
-}
-
-static CDVJKArray *_CDVJKArrayCreate(id *objects, NSUInteger count, BOOL mutableCollection) {
- NSCParameterAssert((objects != NULL) && (_CDVJKArrayClass != NULL) && (_CDVJKArrayInstanceSize > 0UL));
- CDVJKArray *array = NULL;
- if(CDVJK_EXPECT_T((array = (CDVJKArray *)calloc(1UL, _CDVJKArrayInstanceSize)) != NULL)) { // Directly allocate the CDVJKArray instance via calloc.
- array->isa = _CDVJKArrayClass;
- if((array = [array init]) == NULL) { return(NULL); }
- array->capacity = count;
- array->count = count;
- if(CDVJK_EXPECT_F((array->objects = (id *)malloc(sizeof(id) * array->capacity)) == NULL)) { [array autorelease]; return(NULL); }
- memcpy(array->objects, objects, array->capacity * sizeof(id));
- array->mutations = (mutableCollection == NO) ? 0UL : 1UL;
- }
- return(array);
-}
-
-// Note: The caller is responsible for -retaining the object that is to be added.
-static void _CDVJKArrayInsertObjectAtIndex(CDVJKArray *array, id newObject, NSUInteger objectIndex) {
- NSCParameterAssert((array != NULL) && (array->objects != NULL) && (array->count <= array->capacity) && (objectIndex <= array->count) && (newObject != NULL));
- if(!((array != NULL) && (array->objects != NULL) && (objectIndex <= array->count) && (newObject != NULL))) { [newObject autorelease]; return; }
- if((array->count + 1UL) >= array->capacity) {
- id *newObjects = NULL;
- if((newObjects = (id *)realloc(array->objects, sizeof(id) * (array->capacity + 16UL))) == NULL) { [NSException raise:NSMallocException format:@"Unable to resize objects array."]; }
- array->objects = newObjects;
- array->capacity += 16UL;
- memset(&array->objects[array->count], 0, sizeof(id) * (array->capacity - array->count));
- }
- array->count++;
- if((objectIndex + 1UL) < array->count) { memmove(&array->objects[objectIndex + 1UL], &array->objects[objectIndex], sizeof(id) * ((array->count - 1UL) - objectIndex)); array->objects[objectIndex] = NULL; }
- array->objects[objectIndex] = newObject;
-}
-
-// Note: The caller is responsible for -retaining the object that is to be added.
-static void _CDVJKArrayReplaceObjectAtIndexWithObject(CDVJKArray *array, NSUInteger objectIndex, id newObject) {
- NSCParameterAssert((array != NULL) && (array->objects != NULL) && (array->count <= array->capacity) && (objectIndex < array->count) && (array->objects[objectIndex] != NULL) && (newObject != NULL));
- if(!((array != NULL) && (array->objects != NULL) && (objectIndex < array->count) && (array->objects[objectIndex] != NULL) && (newObject != NULL))) { [newObject autorelease]; return; }
- CFRelease(array->objects[objectIndex]);
- array->objects[objectIndex] = NULL;
- array->objects[objectIndex] = newObject;
-}
-
-static void _CDVJKArrayRemoveObjectAtIndex(CDVJKArray *array, NSUInteger objectIndex) {
- NSCParameterAssert((array != NULL) && (array->objects != NULL) && (array->count > 0UL) && (array->count <= array->capacity) && (objectIndex < array->count) && (array->objects[objectIndex] != NULL));
- if(!((array != NULL) && (array->objects != NULL) && (array->count > 0UL) && (array->count <= array->capacity) && (objectIndex < array->count) && (array->objects[objectIndex] != NULL))) { return; }
- CFRelease(array->objects[objectIndex]);
- array->objects[objectIndex] = NULL;
- if((objectIndex + 1UL) < array->count) { memmove(&array->objects[objectIndex], &array->objects[objectIndex + 1UL], sizeof(id) * ((array->count - 1UL) - objectIndex)); array->objects[array->count - 1UL] = NULL; }
- array->count--;
-}
-
-- (void)dealloc
-{
- if(CDVJK_EXPECT_T(objects != NULL)) {
- NSUInteger atObject = 0UL;
- for(atObject = 0UL; atObject < count; atObject++) { if(CDVJK_EXPECT_T(objects[atObject] != NULL)) { CFRelease(objects[atObject]); objects[atObject] = NULL; } }
- free(objects); objects = NULL;
- }
-
- [super dealloc];
-}
-
-- (NSUInteger)count
-{
- NSParameterAssert((objects != NULL) && (count <= capacity));
- return(count);
-}
-
-- (void)getObjects:(id *)objectsPtr range:(NSRange)range
-{
- NSParameterAssert((objects != NULL) && (count <= capacity));
- if((objectsPtr == NULL) && (NSMaxRange(range) > 0UL)) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: pointer to objects array is NULL but range length is %u", NSStringFromClass([self class]), NSStringFromSelector(_cmd), NSMaxRange(range)]; }
- if((range.location > count) || (NSMaxRange(range) > count)) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: index (%u) beyond bounds (%u)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), NSMaxRange(range), count]; }
- if (objectsPtr != NULL) {
- memcpy(objectsPtr, objects + range.location, range.length * sizeof(id));
- }
-}
-
-- (id)objectAtIndex:(NSUInteger)objectIndex
-{
- if(objectIndex >= count) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: index (%u) beyond bounds (%u)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), objectIndex, count]; }
- NSParameterAssert((objects != NULL) && (count <= capacity) && (objects[objectIndex] != NULL));
- return(objects[objectIndex]);
-}
-
-- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
-{
- NSParameterAssert((state != NULL) && (stackbuf != NULL) && (len > 0UL) && (objects != NULL) && (count <= capacity));
- if(CDVJK_EXPECT_F(state->state == 0UL)) { state->mutationsPtr = (unsigned long *)&mutations; state->itemsPtr = stackbuf; }
- if(CDVJK_EXPECT_F(state->state >= count)) { return(0UL); }
-
- NSUInteger enumeratedCount = 0UL;
- while(CDVJK_EXPECT_T(enumeratedCount < len) && CDVJK_EXPECT_T(state->state < count)) { NSParameterAssert(objects[state->state] != NULL); stackbuf[enumeratedCount++] = objects[state->state++]; }
-
- return(enumeratedCount);
-}
-
-- (void)insertObject:(id)anObject atIndex:(NSUInteger)objectIndex
-{
- if(mutations == 0UL) { [NSException raise:NSInternalInconsistencyException format:@"*** -[%@ %@]: mutating method sent to immutable object", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
- if(anObject == NULL) { [NSException raise:NSInvalidArgumentException format:@"*** -[%@ %@]: attempt to insert nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
- if(objectIndex > count) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: index (%u) beyond bounds (%lu)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), objectIndex, count + 1UL]; }
-#ifdef __clang_analyzer__
- [anObject retain]; // Stupid clang analyzer... Issue #19.
-#else
- anObject = [anObject retain];
-#endif
- _CDVJKArrayInsertObjectAtIndex(self, anObject, objectIndex);
- mutations = (mutations == NSUIntegerMax) ? 1UL : mutations + 1UL;
-}
-
-- (void)removeObjectAtIndex:(NSUInteger)objectIndex
-{
- if(mutations == 0UL) { [NSException raise:NSInternalInconsistencyException format:@"*** -[%@ %@]: mutating method sent to immutable object", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
- if(objectIndex >= count) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: index (%u) beyond bounds (%u)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), objectIndex, count]; }
- _CDVJKArrayRemoveObjectAtIndex(self, objectIndex);
- mutations = (mutations == NSUIntegerMax) ? 1UL : mutations + 1UL;
-}
-
-- (void)replaceObjectAtIndex:(NSUInteger)objectIndex withObject:(id)anObject
-{
- if(mutations == 0UL) { [NSException raise:NSInternalInconsistencyException format:@"*** -[%@ %@]: mutating method sent to immutable object", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
- if(anObject == NULL) { [NSException raise:NSInvalidArgumentException format:@"*** -[%@ %@]: attempt to insert nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
- if(objectIndex >= count) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: index (%u) beyond bounds (%u)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), objectIndex, count]; }
-#ifdef __clang_analyzer__
- [anObject retain]; // Stupid clang analyzer... Issue #19.
-#else
- anObject = [anObject retain];
-#endif
- _CDVJKArrayReplaceObjectAtIndexWithObject(self, objectIndex, anObject);
- mutations = (mutations == NSUIntegerMax) ? 1UL : mutations + 1UL;
-}
-
-- (id)copyWithZone:(NSZone *)zone
-{
- NSParameterAssert((objects != NULL) && (count <= capacity));
- return((mutations == 0UL) ? [self retain] : [(NSArray *)[NSArray allocWithZone:zone] initWithObjects:objects count:count]);
-}
-
-- (id)mutableCopyWithZone:(NSZone *)zone
-{
- NSParameterAssert((objects != NULL) && (count <= capacity));
- return([(NSMutableArray *)[NSMutableArray allocWithZone:zone] initWithObjects:objects count:count]);
-}
-
-@end
-
-
-#pragma mark -
-@interface CDVJKDictionaryEnumerator : NSEnumerator {
- id collection;
- NSUInteger nextObject;
-}
-
-- (id)initWithJKDictionary:(CDVJKDictionary *)initDictionary;
-- (NSArray *)allObjects;
-- (id)nextObject;
-
-@end
-
-@implementation CDVJKDictionaryEnumerator
-
-- (id)initWithJKDictionary:(CDVJKDictionary *)initDictionary
-{
- NSParameterAssert(initDictionary != NULL);
- if((self = [super init]) == NULL) { return(NULL); }
- if((collection = (id)CFRetain(initDictionary)) == NULL) { [self autorelease]; return(NULL); }
- return(self);
-}
-
-- (void)dealloc
-{
- if(collection != NULL) { CFRelease(collection); collection = NULL; }
- [super dealloc];
-}
-
-- (NSArray *)allObjects
-{
- NSParameterAssert(collection != NULL);
- NSUInteger count = [collection count], atObject = 0UL;
- id objects[count];
-
- while((objects[atObject] = [self nextObject]) != NULL) { NSParameterAssert(atObject < count); atObject++; }
-
- return([NSArray arrayWithObjects:objects count:atObject]);
-}
-
-- (id)nextObject
-{
- NSParameterAssert((collection != NULL) && (_CDVJKDictionaryHashEntry(collection) != NULL));
- CDVJKHashTableEntry *entry = _CDVJKDictionaryHashEntry(collection);
- NSUInteger capacity = _CDVJKDictionaryCapacity(collection);
- id returnObject = NULL;
-
- if(entry != NULL) { while((nextObject < capacity) && ((returnObject = entry[nextObject++].key) == NULL)) { /* ... */ } }
-
- return(returnObject);
-}
-
-@end
-
-#pragma mark -
-@interface CDVJKDictionary : NSMutableDictionary <NSCopying, NSMutableCopying, NSFastEnumeration> {
- NSUInteger count, capacity, mutations;
- CDVJKHashTableEntry *entry;
-}
-@end
-
-@implementation CDVJKDictionary
-
-+ (id)allocWithZone:(NSZone *)zone
-{
-#pragma unused(zone)
- [NSException raise:NSInvalidArgumentException format:@"*** - [%@ %@]: The %@ class is private to CDVJSONKit and should not be used in this fashion.", NSStringFromClass([self class]), NSStringFromSelector(_cmd), NSStringFromClass([self class])];
- return(NULL);
-}
-
-// These values are taken from Core Foundation CF-550 CFBasicHash.m. As a bonus, they align very well with our CDVJKHashTableEntry struct too.
-static const NSUInteger cdvjk_dictionaryCapacities[] = {
- 0UL, 3UL, 7UL, 13UL, 23UL, 41UL, 71UL, 127UL, 191UL, 251UL, 383UL, 631UL, 1087UL, 1723UL,
- 2803UL, 4523UL, 7351UL, 11959UL, 19447UL, 31231UL, 50683UL, 81919UL, 132607UL,
- 214519UL, 346607UL, 561109UL, 907759UL, 1468927UL, 2376191UL, 3845119UL,
- 6221311UL, 10066421UL, 16287743UL, 26354171UL, 42641881UL, 68996069UL,
- 111638519UL, 180634607UL, 292272623UL, 472907251UL
-};
-
-static NSUInteger _CDVJKDictionaryCapacityForCount(NSUInteger count) {
- NSUInteger bottom = 0UL, top = sizeof(cdvjk_dictionaryCapacities) / sizeof(NSUInteger), mid = 0UL, tableSize = lround(floor((count) * 1.33));
- while(top > bottom) { mid = (top + bottom) / 2UL; if(cdvjk_dictionaryCapacities[mid] < tableSize) { bottom = mid + 1UL; } else { top = mid; } }
- return(cdvjk_dictionaryCapacities[bottom]);
-}
-
-static void _CDVJKDictionaryResizeIfNeccessary(CDVJKDictionary *dictionary) {
- NSCParameterAssert((dictionary != NULL) && (dictionary->entry != NULL) && (dictionary->count <= dictionary->capacity));
-
- NSUInteger capacityForCount = 0UL;
- if(dictionary->capacity < (capacityForCount = _CDVJKDictionaryCapacityForCount(dictionary->count + 1UL))) { // resize
- NSUInteger oldCapacity = dictionary->capacity;
-#ifndef NS_BLOCK_ASSERTIONS
- NSUInteger oldCount = dictionary->count;
-#endif
- CDVJKHashTableEntry *oldEntry = dictionary->entry;
- if(CDVJK_EXPECT_F((dictionary->entry = (CDVJKHashTableEntry *)calloc(1UL, sizeof(CDVJKHashTableEntry) * capacityForCount)) == NULL)) { [NSException raise:NSMallocException format:@"Unable to allocate memory for hash table."]; }
- dictionary->capacity = capacityForCount;
- dictionary->count = 0UL;
-
- NSUInteger idx = 0UL;
- for(idx = 0UL; idx < oldCapacity; idx++) { if(oldEntry[idx].key != NULL) { _CDVJKDictionaryAddObject(dictionary, oldEntry[idx].keyHash, oldEntry[idx].key, oldEntry[idx].object); oldEntry[idx].keyHash = 0UL; oldEntry[idx].key = NULL; oldEntry[idx].object = NULL; } }
- NSCParameterAssert((oldCount == dictionary->count));
- free(oldEntry); oldEntry = NULL;
- }
-}
-
-static CDVJKDictionary *_CDVJKDictionaryCreate(id *keys, NSUInteger *keyHashes, id *objects, NSUInteger count, BOOL mutableCollection) {
- NSCParameterAssert((keys != NULL) && (keyHashes != NULL) && (objects != NULL) && (_CDVJKDictionaryClass != NULL) && (_CDVJKDictionaryInstanceSize > 0UL));
- CDVJKDictionary *dictionary = NULL;
- if(CDVJK_EXPECT_T((dictionary = (CDVJKDictionary *)calloc(1UL, _CDVJKDictionaryInstanceSize)) != NULL)) { // Directly allocate the CDVJKDictionary instance via calloc.
- dictionary->isa = _CDVJKDictionaryClass;
- if((dictionary = [dictionary init]) == NULL) { return(NULL); }
- dictionary->capacity = _CDVJKDictionaryCapacityForCount(count);
- dictionary->count = 0UL;
-
- if(CDVJK_EXPECT_F((dictionary->entry = (CDVJKHashTableEntry *)calloc(1UL, sizeof(CDVJKHashTableEntry) * dictionary->capacity)) == NULL)) { [dictionary autorelease]; return(NULL); }
-
- NSUInteger idx = 0UL;
- for(idx = 0UL; idx < count; idx++) { _CDVJKDictionaryAddObject(dictionary, keyHashes[idx], keys[idx], objects[idx]); }
-
- dictionary->mutations = (mutableCollection == NO) ? 0UL : 1UL;
- }
- return(dictionary);
-}
-
-- (void)dealloc
-{
- if(CDVJK_EXPECT_T(entry != NULL)) {
- NSUInteger atEntry = 0UL;
- for(atEntry = 0UL; atEntry < capacity; atEntry++) {
- if(CDVJK_EXPECT_T(entry[atEntry].key != NULL)) { CFRelease(entry[atEntry].key); entry[atEntry].key = NULL; }
- if(CDVJK_EXPECT_T(entry[atEntry].object != NULL)) { CFRelease(entry[atEntry].object); entry[atEntry].object = NULL; }
- }
-
- free(entry); entry = NULL;
- }
-
- [super dealloc];
-}
-
-static CDVJKHashTableEntry *_CDVJKDictionaryHashEntry(CDVJKDictionary *dictionary) {
- NSCParameterAssert(dictionary != NULL);
- return(dictionary->entry);
-}
-
-static NSUInteger _CDVJKDictionaryCapacity(CDVJKDictionary *dictionary) {
- NSCParameterAssert(dictionary != NULL);
- return(dictionary->capacity);
-}
-
-static void _CDVJKDictionaryRemoveObjectWithEntry(CDVJKDictionary *dictionary, CDVJKHashTableEntry *entry) {
- NSCParameterAssert((dictionary != NULL) && (entry != NULL) && (entry->key != NULL) && (entry->object != NULL) && (dictionary->count > 0UL) && (dictionary->count <= dictionary->capacity));
- CFRelease(entry->key); entry->key = NULL;
- CFRelease(entry->object); entry->object = NULL;
- entry->keyHash = 0UL;
- dictionary->count--;
- // In order for certain invariants that are used to speed up the search for a particular key, we need to "re-add" all the entries in the hash table following this entry until we hit a NULL entry.
- NSUInteger removeIdx = entry - dictionary->entry, idx = 0UL;
- NSCParameterAssert((removeIdx < dictionary->capacity));
- for(idx = 0UL; idx < dictionary->capacity; idx++) {
- NSUInteger entryIdx = (removeIdx + idx + 1UL) % dictionary->capacity;
- CDVJKHashTableEntry *atEntry = &dictionary->entry[entryIdx];
- if(atEntry->key == NULL) { break; }
- NSUInteger keyHash = atEntry->keyHash;
- id key = atEntry->key, object = atEntry->object;
- NSCParameterAssert(object != NULL);
- atEntry->keyHash = 0UL;
- atEntry->key = NULL;
- atEntry->object = NULL;
- NSUInteger addKeyEntry = keyHash % dictionary->capacity, addIdx = 0UL;
- for(addIdx = 0UL; addIdx < dictionary->capacity; addIdx++) {
- CDVJKHashTableEntry *atAddEntry = &dictionary->entry[((addKeyEntry + addIdx) % dictionary->capacity)];
- if(CDVJK_EXPECT_T(atAddEntry->key == NULL)) { NSCParameterAssert((atAddEntry->keyHash == 0UL) && (atAddEntry->object == NULL)); atAddEntry->key = key; atAddEntry->object = object; atAddEntry->keyHash = keyHash; break; }
- }
- }
-}
-
-static void _CDVJKDictionaryAddObject(CDVJKDictionary *dictionary, NSUInteger keyHash, id key, id object) {
- NSCParameterAssert((dictionary != NULL) && (key != NULL) && (object != NULL) && (dictionary->count < dictionary->capacity) && (dictionary->entry != NULL));
- NSUInteger keyEntry = keyHash % dictionary->capacity, idx = 0UL;
- for(idx = 0UL; idx < dictionary->capacity; idx++) {
- NSUInteger entryIdx = (keyEntry + idx) % dictionary->capacity;
- CDVJKHashTableEntry *atEntry = &dictionary->entry[entryIdx];
- if(CDVJK_EXPECT_F(atEntry->keyHash == keyHash) && CDVJK_EXPECT_T(atEntry->key != NULL) && (CDVJK_EXPECT_F(key == atEntry->key) || CDVJK_EXPECT_F(CFEqual(atEntry->key, key)))) { _CDVJKDictionaryRemoveObjectWithEntry(dictionary, atEntry); }
- if(CDVJK_EXPECT_T(atEntry->key == NULL)) { NSCParameterAssert((atEntry->keyHash == 0UL) && (atEntry->object == NULL)); atEntry->key = key; atEntry->object = object; atEntry->keyHash = keyHash; dictionary->count++; return; }
- }
-
- // We should never get here. If we do, we -release the key / object because it's our responsibility.
- CFRelease(key);
- CFRelease(object);
-}
-
-- (NSUInteger)count
-{
- return(count);
-}
-
-static CDVJKHashTableEntry *_CDVJKDictionaryHashTableEntryForKey(CDVJKDictionary *dictionary, id aKey) {
- NSCParameterAssert((dictionary != NULL) && (dictionary->entry != NULL) && (dictionary->count <= dictionary->capacity));
- if((aKey == NULL) || (dictionary->capacity == 0UL)) { return(NULL); }
- NSUInteger keyHash = CFHash(aKey), keyEntry = (keyHash % dictionary->capacity), idx = 0UL;
- CDVJKHashTableEntry *atEntry = NULL;
- for(idx = 0UL; idx < dictionary->capacity; idx++) {
- atEntry = &dictionary->entry[(keyEntry + idx) % dictionary->capacity];
- if(CDVJK_EXPECT_T(atEntry->keyHash == keyHash) && CDVJK_EXPECT_T(atEntry->key != NULL) && ((atEntry->key == aKey) || CFEqual(atEntry->key, aKey))) { NSCParameterAssert(atEntry->object != NULL); return(atEntry); break; }
- if(CDVJK_EXPECT_F(atEntry->key == NULL)) { NSCParameterAssert(atEntry->object == NULL); return(NULL); break; } // If the key was in the table, we would have found it by now.
- }
- return(NULL);
-}
-
-- (id)objectForKey:(id)aKey
-{
- NSParameterAssert((entry != NULL) && (count <= capacity));
- CDVJKHashTableEntry *entryForKey = _CDVJKDictionaryHashTableEntryForKey(self, aKey);
- return((entryForKey != NULL) ? entryForKey->object : NULL);
-}
-
-- (void)getObjects:(id *)objects andKeys:(id *)keys
-{
- NSParameterAssert((entry != NULL) && (count <= capacity));
- NSUInteger atEntry = 0UL; NSUInteger arrayIdx = 0UL;
- for(atEntry = 0UL; atEntry < capacity; atEntry++) {
- if(CDVJK_EXPECT_T(entry[atEntry].key != NULL)) {
- NSCParameterAssert((entry[atEntry].object != NULL) && (arrayIdx < count));
- if(CDVJK_EXPECT_T(keys != NULL)) { keys[arrayIdx] = entry[atEntry].key; }
- if(CDVJK_EXPECT_T(objects != NULL)) { objects[arrayIdx] = entry[atEntry].object; }
- arrayIdx++;
- }
- }
-}
-
-- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
-{
- NSParameterAssert((state != NULL) && (stackbuf != NULL) && (len > 0UL) && (entry != NULL) && (count <= capacity));
- if(CDVJK_EXPECT_F(state->state == 0UL)) { state->mutationsPtr = (unsigned long *)&mutations; state->itemsPtr = stackbuf; }
- if(CDVJK_EXPECT_F(state->state >= capacity)) { return(0UL); }
-
- NSUInteger enumeratedCount = 0UL;
- while(CDVJK_EXPECT_T(enumeratedCount < len) && CDVJK_EXPECT_T(state->state < capacity)) { if(CDVJK_EXPECT_T(entry[state->state].key != NULL)) { stackbuf[enumeratedCount++] = entry[state->state].key; } state->state++; }
-
- return(enumeratedCount);
-}
-
-- (NSEnumerator *)keyEnumerator
-{
- return([[[CDVJKDictionaryEnumerator alloc] initWithJKDictionary:self] autorelease]);
-}
-
-- (void)setObject:(id)anObject forKey:(id)aKey
-{
- if(mutations == 0UL) { [NSException raise:NSInternalInconsistencyException format:@"*** -[%@ %@]: mutating method sent to immutable object", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
- if(aKey == NULL) { [NSException raise:NSInvalidArgumentException format:@"*** -[%@ %@]: attempt to insert nil key", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
- if(anObject == NULL) { [NSException raise:NSInvalidArgumentException format:@"*** -[%@ %@]: attempt to insert nil value (key: %@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), aKey]; }
-
- _CDVJKDictionaryResizeIfNeccessary(self);
-#ifndef __clang_analyzer__
- aKey = [aKey copy]; // Why on earth would clang complain that this -copy "might leak",
- anObject = [anObject retain]; // but this -retain doesn't!?
-#endif // __clang_analyzer__
- _CDVJKDictionaryAddObject(self, CFHash(aKey), aKey, anObject);
- mutations = (mutations == NSUIntegerMax) ? 1UL : mutations + 1UL;
-}
-
-- (void)removeObjectForKey:(id)aKey
-{
- if(mutations == 0UL) { [NSException raise:NSInternalInconsistencyException format:@"*** -[%@ %@]: mutating method sent to immutable object", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
- if(aKey == NULL) { [NSException raise:NSInvalidArgumentException format:@"*** -[%@ %@]: attempt to remove nil key", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
- CDVJKHashTableEntry *entryForKey = _CDVJKDictionaryHashTableEntryForKey(self, aKey);
- if(entryForKey != NULL) {
- _CDVJKDictionaryRemoveObjectWithEntry(self, entryForKey);
- mutations = (mutations == NSUIntegerMax) ? 1UL : mutations + 1UL;
- }
-}
-
-- (id)copyWithZone:(NSZone *)zone
-{
- NSParameterAssert((entry != NULL) && (count <= capacity));
- return((mutations == 0UL) ? [self retain] : [[NSDictionary allocWithZone:zone] initWithDictionary:self]);
-}
-
-- (id)mutableCopyWithZone:(NSZone *)zone
-{
- NSParameterAssert((entry != NULL) && (count <= capacity));
- return([[NSMutableDictionary allocWithZone:zone] initWithDictionary:self]);
-}
-
-@end
-
-
-
-#pragma mark -
-
-CDVJK_STATIC_INLINE size_t cdvjk_min(size_t a, size_t b) { return((a < b) ? a : b); }
-CDVJK_STATIC_INLINE size_t cdvjk_max(size_t a, size_t b) { return((a > b) ? a : b); }
-
-CDVJK_STATIC_INLINE CDVJKHash cdvcalculateHash(CDVJKHash currentHash, unsigned char c) { return(((currentHash << 5) + currentHash) + c); }
-
-static void cdvjk_error(CDVJKParseState *parseState, NSString *format, ...) {
- NSCParameterAssert((parseState != NULL) && (format != NULL));
-
- va_list varArgsList;
- va_start(varArgsList, format);
- NSString *formatString = [[[NSString alloc] initWithFormat:format arguments:varArgsList] autorelease];
- va_end(varArgsList);
-
-#if 0
- const unsigned char *lineStart = parseState->stringBuffer.bytes.ptr + parseState->lineStartIndex;
- const unsigned char *lineEnd = lineStart;
- const unsigned char *atCharacterPtr = NULL;
-
- for(atCharacterPtr = lineStart; atCharacterPtr < CDVJK_END_STRING_PTR(parseState); atCharacterPtr++) { lineEnd = atCharacterPtr; if(cdvjk_parse_is_newline(parseState, atCharacterPtr)) { break; } }
-
- NSString *lineString = @"", *carretString = @"";
- if(lineStart < CDVJK_END_STRING_PTR(parseState)) {
- lineString = [[[NSString alloc] initWithBytes:lineStart length:(lineEnd - lineStart) encoding:NSUTF8StringEncoding] autorelease];
- carretString = [NSString stringWithFormat:@"%*.*s^", (int)(parseState->atIndex - parseState->lineStartIndex), (int)(parseState->atIndex - parseState->lineStartIndex), " "];
- }
-#endif
-
- if(parseState->error == NULL) {
- parseState->error = [NSError errorWithDomain:@"CDVJKErrorDomain" code:-1L userInfo:
- [NSDictionary dictionaryWithObjectsAndKeys:
- formatString, NSLocalizedDescriptionKey,
- [NSNumber numberWithUnsignedLong:parseState->atIndex], @"CDVJKAtIndexKey",
- [NSNumber numberWithUnsignedLong:parseState->lineNumber], @"CDVJKLineNumberKey",
- //lineString, @"CDVJKErrorLine0Key",
- //carretString, @"CDVJKErrorLine1Key",
- NULL]];
- }
-}
-
-#pragma mark -
-#pragma mark Buffer and Object Stack management functions
-
-static void cdvjk_managedBuffer_release(CDVJKManagedBuffer *managedBuffer) {
- if((managedBuffer->flags & CDVJKManagedBufferMustFree)) {
- if(managedBuffer->bytes.ptr != NULL) { free(managedBuffer->bytes.ptr); managedBuffer->bytes.ptr = NULL; }
- managedBuffer->flags &= ~CDVJKManagedBufferMustFree;
- }
-
- managedBuffer->bytes.ptr = NULL;
- managedBuffer->bytes.length = 0UL;
- managedBuffer->flags &= ~CDVJKManagedBufferLocationMask;
-}
-
-static void cdvjk_managedBuffer_setToStackBuffer(CDVJKManagedBuffer *managedBuffer, unsigned char *ptr, size_t length) {
- cdvjk_managedBuffer_release(managedBuffer);
- managedBuffer->bytes.ptr = ptr;
- managedBuffer->bytes.length = length;
- managedBuffer->flags = (managedBuffer->flags & ~CDVJKManagedBufferLocationMask) | CDVJKManagedBufferOnStack;
-}
-
-static unsigned char *cdvjk_managedBuffer_resize(CDVJKManagedBuffer *managedBuffer, size_t newSize) {
- size_t roundedUpNewSize = newSize;
-
- if(managedBuffer->roundSizeUpToMultipleOf > 0UL) { roundedUpNewSize = newSize + ((managedBuffer->roundSizeUpToMultipleOf - (newSize % managedBuffer->roundSizeUpToMultipleOf)) % managedBuffer->roundSizeUpToMultipleOf); }
-
- if((roundedUpNewSize != managedBuffer->bytes.length) && (roundedUpNewSize > managedBuffer->bytes.length)) {
- if((managedBuffer->flags & CDVJKManagedBufferLocationMask) == CDVJKManagedBufferOnStack) {
- NSCParameterAssert((managedBuffer->flags & CDVJKManagedBufferMustFree) == 0);
- unsigned char *newBuffer = NULL, *oldBuffer = managedBuffer->bytes.ptr;
-
- if((newBuffer = (unsigned char *)malloc(roundedUpNewSize)) == NULL) { return(NULL); }
- memcpy(newBuffer, oldBuffer, cdvjk_min(managedBuffer->bytes.length, roundedUpNewSize));
- managedBuffer->flags = (managedBuffer->flags & ~CDVJKManagedBufferLocationMask) | (CDVJKManagedBufferOnHeap | CDVJKManagedBufferMustFree);
- managedBuffer->bytes.ptr = newBuffer;
- managedBuffer->bytes.length = roundedUpNewSize;
- } else {
- NSCParameterAssert(((managedBuffer->flags & CDVJKManagedBufferMustFree) != 0) && ((managedBuffer->flags & CDVJKManagedBufferLocationMask) == CDVJKManagedBufferOnHeap));
- if((managedBuffer->bytes.ptr = (unsigned char *)reallocf(managedBuffer->bytes.ptr, roundedUpNewSize)) == NULL) { return(NULL); }
- managedBuffer->bytes.length = roundedUpNewSize;
- }
- }
-
- return(managedBuffer->bytes.ptr);
-}
-
-
-
-static void cdvjk_objectStack_release(CDVJKObjectStack *objectStack) {
- NSCParameterAssert(objectStack != NULL);
-
- NSCParameterAssert(objectStack->index <= objectStack->count);
- size_t atIndex = 0UL;
- for(atIndex = 0UL; atIndex < objectStack->index; atIndex++) {
- if(objectStack->objects[atIndex] != NULL) { CFRelease(objectStack->objects[atIndex]); objectStack->objects[atIndex] = NULL; }
- if(objectStack->keys[atIndex] != NULL) { CFRelease(objectStack->keys[atIndex]); objectStack->keys[atIndex] = NULL; }
- }
- objectStack->index = 0UL;
-
- if(objectStack->flags & CDVJKObjectStackMustFree) {
- NSCParameterAssert((objectStack->flags & CDVJKObjectStackLocationMask) == CDVJKObjectStackOnHeap);
- if(objectStack->objects != NULL) { free(objectStack->objects); objectStack->objects = NULL; }
- if(objectStack->keys != NULL) { free(objectStack->keys); objectStack->keys = NULL; }
- if(objectStack->cfHashes != NULL) { free(objectStack->cfHashes); objectStack->cfHashes = NULL; }
- objectStack->flags &= ~CDVJKObjectStackMustFree;
- }
-
- objectStack->objects = NULL;
- objectStack->keys = NULL;
- objectStack->cfHashes = NULL;
-
- objectStack->count = 0UL;
- objectStack->flags &= ~CDVJKObjectStackLocationMask;
-}
-
-static void cdvjk_objectStack_setToStackBuffer(CDVJKObjectStack *objectStack, void **objects, void **keys, CFHashCode *cfHashes, size_t count) {
- NSCParameterAssert((objectStack != NULL) && (objects != NULL) && (keys != NULL) && (cfHashes != NULL) && (count > 0UL));
- cdvjk_objectStack_release(objectStack);
- objectStack->objects = objects;
- objectStack->keys = keys;
- objectStack->cfHashes = cfHashes;
- objectStack->count = count;
- objectStack->flags = (objectStack->flags & ~CDVJKObjectStackLocationMask) | CDVJKObjectStackOnStack;
-#ifndef NS_BLOCK_ASSERTIONS
- size_t idx;
- for(idx = 0UL; idx < objectStack->count; idx++) { objectStack->objects[idx] = NULL; objectStack->keys[idx] = NULL; objectStack->cfHashes[idx] = 0UL; }
-#endif
-}
-
-static int cdvjk_objectStack_resize(CDVJKObjectStack *objectStack, size_t newCount) {
- size_t roundedUpNewCount = newCount;
- int returnCode = 0;
-
- void **newObjects = NULL, **newKeys = NULL;
- CFHashCode *newCFHashes = NULL;
-
- if(objectStack->roundSizeUpToMultipleOf > 0UL) { roundedUpNewCount = newCount + ((objectStack->roundSizeUpToMultipleOf - (newCount % objectStack->roundSizeUpToMultipleOf)) % objectStack->roundSizeUpToMultipleOf); }
-
- if((roundedUpNewCount != objectStack->count) && (roundedUpNewCount > objectStack->count)) {
- if((objectStack->flags & CDVJKObjectStackLocationMask) == CDVJKObjectStackOnStack) {
- NSCParameterAssert((objectStack->flags & CDVJKObjectStackMustFree) == 0);
-
- if((newObjects = (void ** )calloc(1UL, roundedUpNewCount * sizeof(void * ))) == NULL) { returnCode = 1; goto errorExit; }
- memcpy(newObjects, objectStack->objects, cdvjk_min(objectStack->count, roundedUpNewCount) * sizeof(void *));
- if((newKeys = (void ** )calloc(1UL, roundedUpNewCount * sizeof(void * ))) == NULL) { returnCode = 1; goto errorExit; }
- memcpy(newKeys, objectStack->keys, cdvjk_min(objectStack->count, roundedUpNewCount) * sizeof(void *));
-
- if((newCFHashes = (CFHashCode *)calloc(1UL, roundedUpNewCount * sizeof(CFHashCode))) == NULL) { returnCode = 1; goto errorExit; }
- memcpy(newCFHashes, objectStack->cfHashes, cdvjk_min(objectStack->count, roundedUpNewCount) * sizeof(CFHashCode));
-
- objectStack->flags = (objectStack->flags & ~CDVJKObjectStackLocationMask) | (CDVJKObjectStackOnHeap | CDVJKObjectStackMustFree);
- objectStack->objects = newObjects; newObjects = NULL;
- objectStack->keys = newKeys; newKeys = NULL;
- objectStack->cfHashes = newCFHashes; newCFHashes = NULL;
- objectStack->count = roundedUpNewCount;
- } else {
- NSCParameterAssert(((objectStack->flags & CDVJKObjectStackMustFree) != 0) && ((objectStack->flags & CDVJKObjectStackLocationMask) == CDVJKObjectStackOnHeap));
- if((newObjects = (void ** )realloc(objectStack->objects, roundedUpNewCount * sizeof(void * ))) != NULL) { objectStack->objects = newObjects; newObjects = NULL; } else { returnCode = 1; goto errorExit; }
- if((newKeys = (void ** )realloc(objectStack->keys, roundedUpNewCount * sizeof(void * ))) != NULL) { objectStack->keys = newKeys; newKeys = NULL; } else { returnCode = 1; goto errorExit; }
- if((newCFHashes = (CFHashCode *)realloc(objectStack->cfHashes, roundedUpNewCount * sizeof(CFHashCode))) != NULL) { objectStack->cfHashes = newCFHashes; newCFHashes = NULL; } else { returnCode = 1; goto errorExit; }
-
-#ifndef NS_BLOCK_ASSERTIONS
- size_t idx;
- for(idx = objectStack->count; idx < roundedUpNewCount; idx++) { objectStack->objects[idx] = NULL; objectStack->keys[idx] = NULL; objectStack->cfHashes[idx] = 0UL; }
-#endif
- objectStack->count = roundedUpNewCount;
- }
- }
-
- errorExit:
- if(newObjects != NULL) { free(newObjects); newObjects = NULL; }
- if(newKeys != NULL) { free(newKeys); newKeys = NULL; }
- if(newCFHashes != NULL) { free(newCFHashes); newCFHashes = NULL; }
-
- return(returnCode);
-}
-
-////////////
-#pragma mark -
-#pragma mark Unicode related functions
-
-CDVJK_STATIC_INLINE CDV_ConversionResult cdvisValidCodePoint(UTF32 *u32CodePoint) {
- CDV_ConversionResult result = conversionOK;
- UTF32 ch = *u32CodePoint;
-
- if(CDVJK_EXPECT_F(ch >= CDV_UNI_SUR_HIGH_START) && (CDVJK_EXPECT_T(ch <= CDV_UNI_SUR_LOW_END))) { result = sourceIllegal; ch = CDV_UNI_REPLACEMENT_CHAR; goto finished; }
- if(CDVJK_EXPECT_F(ch >= 0xFDD0U) && (CDVJK_EXPECT_F(ch <= 0xFDEFU) || CDVJK_EXPECT_F((ch & 0xFFFEU) == 0xFFFEU)) && CDVJK_EXPECT_T(ch <= 0x10FFFFU)) { result = sourceIllegal; ch = CDV_UNI_REPLACEMENT_CHAR; goto finished; }
- if(CDVJK_EXPECT_F(ch == 0U)) { result = sourceIllegal; ch = CDV_UNI_REPLACEMENT_CHAR; goto finished; }
-
- finished:
- *u32CodePoint = ch;
- return(result);
-}
-
-
-static int cdvisLegalUTF8(const UTF8 *source, size_t length) {
- const UTF8 *srcptr = source + length;
- UTF8 a;
-
- switch(length) {
- default: return(0); // Everything else falls through when "true"...
- case 4: if(CDVJK_EXPECT_F(((a = (*--srcptr)) < 0x80) || (a > 0xBF))) { return(0); }
- case 3: if(CDVJK_EXPECT_F(((a = (*--srcptr)) < 0x80) || (a > 0xBF))) { return(0); }
- case 2: if(CDVJK_EXPECT_F( (a = (*--srcptr)) > 0xBF )) { return(0); }
-
- switch(*source) { // no fall-through in this inner switch
- case 0xE0: if(CDVJK_EXPECT_F(a < 0xA0)) { return(0); } break;
- case 0xED: if(CDVJK_EXPECT_F(a > 0x9F)) { return(0); } break;
- case 0xF0: if(CDVJK_EXPECT_F(a < 0x90)) { return(0); } break;
- case 0xF4: if(CDVJK_EXPECT_F(a > 0x8F)) { return(0); } break;
- default: if(CDVJK_EXPECT_F(a < 0x80)) { return(0); }
- }
-
- case 1: if(CDVJK_EXPECT_F((CDVJK_EXPECT_T(*source < 0xC2)) && CDVJK_EXPECT_F(*source >= 0x80))) { return(0); }
- }
-
- if(CDVJK_EXPECT_F(*source > 0xF4)) { return(0); }
-
- return(1);
-}
-
-static CDV_ConversionResult cdvConvertSingleCodePointInUTF8(const UTF8 *sourceStart, const UTF8 *sourceEnd, UTF8 const **nextUTF8, UTF32 *convertedUTF32) {
- CDV_ConversionResult result = conversionOK;
- const UTF8 *source = sourceStart;
- UTF32 ch = 0UL;
-
-#if !defined(CDVJK_FAST_TRAILING_BYTES)
- unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
-#else
- unsigned short extraBytesToRead = __builtin_clz(((*source)^0xff) << 25);
-#endif
-
- if(CDVJK_EXPECT_F((source + extraBytesToRead + 1) > sourceEnd) || CDVJK_EXPECT_F(!cdvisLegalUTF8(source, extraBytesToRead + 1))) {
- source++;
- while((source < sourceEnd) && (((*source) & 0xc0) == 0x80) && ((source - sourceStart) < (extraBytesToRead + 1))) { source++; }
- NSCParameterAssert(source <= sourceEnd);
- result = ((source < sourceEnd) && (((*source) & 0xc0) != 0x80)) ? sourceIllegal : ((sourceStart + extraBytesToRead + 1) > sourceEnd) ? sourceExhausted : sourceIllegal;
- ch = CDV_UNI_REPLACEMENT_CHAR;
- goto finished;
- }
-
- switch(extraBytesToRead) { // The cases all fall through.
- case 5: ch += *source++; ch <<= 6;
- case 4: ch += *source++; ch <<= 6;
- case 3: ch += *source++; ch <<= 6;
- case 2: ch += *source++; ch <<= 6;
- case 1: ch += *source++; ch <<= 6;
- case 0: ch += *source++;
- }
- ch -= offsetsFromUTF8[extraBytesToRead];
-
- result = cdvisValidCodePoint(&ch);
-
- finished:
- *nextUTF8 = source;
- *convertedUTF32 = ch;
-
- return(result);
-}
-
-
-static CDV_ConversionResult cdvConvertUTF32toUTF8 (UTF32 u32CodePoint, UTF8 **targetStart, UTF8 *targetEnd) {
- const UTF32 byteMask = 0xBF, byteMark = 0x80;
- CDV_ConversionResult result = conversionOK;
- UTF8 *target = *targetStart;
- UTF32 ch = u32CodePoint;
- unsigned short bytesToWrite = 0;
-
- result = cdvisValidCodePoint(&ch);
-
- // Figure out how many bytes the result will require. Turn any illegally large UTF32 things (> Plane 17) into replacement chars.
- if(ch < (UTF32)0x80) { bytesToWrite = 1; }
- else if(ch < (UTF32)0x800) { bytesToWrite = 2; }
- else if(ch < (UTF32)0x10000) { bytesToWrite = 3; }
- else if(ch <= CDV_UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; }
- else { bytesToWrite = 3; ch = CDV_UNI_REPLACEMENT_CHAR; result = sourceIllegal; }
-
- target += bytesToWrite;
- if (target > targetEnd) { target -= bytesToWrite; result = targetExhausted; goto finished; }
-
- switch (bytesToWrite) { // note: everything falls through.
- case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
- }
-
- target += bytesToWrite;
-
- finished:
- *targetStart = target;
- return(result);
-}
-
-CDVJK_STATIC_INLINE int cdvjk_string_add_unicodeCodePoint(CDVJKParseState *parseState, uint32_t unicodeCodePoint, size_t *tokenBufferIdx, CDVJKHash *stringHash) {
- UTF8 *u8s = &parseState->token.tokenBuffer.bytes.ptr[*tokenBufferIdx];
- CDV_ConversionResult result;
-
- if((result = cdvConvertUTF32toUTF8(unicodeCodePoint, &u8s, (parseState->token.tokenBuffer.bytes.ptr + parseState->token.tokenBuffer.bytes.length))) != conversionOK) { if(result == targetExhausted) { return(1); } }
- size_t utf8len = u8s - &parseState->token.tokenBuffer.bytes.ptr[*tokenBufferIdx], nextIdx = (*tokenBufferIdx) + utf8len;
-
- while(*tokenBufferIdx < nextIdx) { *stringHash = cdvcalculateHash(*stringHash, parseState->token.tokenBuffer.bytes.ptr[(*tokenBufferIdx)++]); }
-
- return(0);
-}
-
-////////////
-#pragma mark -
-#pragma mark Decoding / parsing / deserializing functions
-
-static int cdvjk_parse_string(CDVJKParseState *parseState) {
- NSCParameterAssert((parseState != NULL) && (CDVJK_AT_STRING_PTR(parseState) <= CDVJK_END_STRING_PTR(parseState)));
- const unsigned char *stringStart = CDVJK_AT_STRING_PTR(parseState) + 1;
- const unsigned char *endOfBuffer = CDVJK_END_STRING_PTR(parseState);
- const unsigned char *atStringCharacter = stringStart;
- unsigned char *tokenBuffer = parseState->token.tokenBuffer.bytes.ptr;
- size_t tokenStartIndex = parseState->atIndex;
- size_t tokenBufferIdx = 0UL;
-
- int onlySimpleString = 1, stringState = CDVJSONStringStateStart;
- uint16_t escapedUnicode1 = 0U, escapedUnicode2 = 0U;
- uint32_t escapedUnicodeCodePoint = 0U;
- CDVJKHash stringHash = CDVJK_HASH_INIT;
-
- while(1) {
- unsigned long currentChar;
-
- if(CDVJK_EXPECT_F(atStringCharacter == endOfBuffer)) { /* XXX Add error message */ stringState = CDVJSONStringStateError; goto finishedParsing; }
-
- if(CDVJK_EXPECT_F((currentChar = *atStringCharacter++) >= 0x80UL)) {
- const unsigned char *nextValidCharacter = NULL;
- UTF32 u32ch = 0U;
- CDV_ConversionResult result;
-
- if(CDVJK_EXPECT_F((result = cdvConvertSingleCodePointInUTF8(atStringCharacter - 1, endOfBuffer, (UTF8 const **)&nextValidCharacter, &u32ch)) != conversionOK)) { goto switchToSlowPath; }
- stringHash = cdvcalculateHash(stringHash, currentChar);
- while(atStringCharacter < nextValidCharacter) { NSCParameterAssert(CDVJK_AT_STRING_PTR(parseState) <= CDVJK_END_STRING_PTR(parseState)); stringHash = cdvcalculateHash(stringHash, *atStringCharacter++); }
- continue;
- } else {
- if(CDVJK_EXPECT_F(currentChar == (unsigned long)'"')) { stringState = CDVJSONStringStateFinished; goto finishedParsing; }
-
- if(CDVJK_EXPECT_F(currentChar == (unsigned long)'\\')) {
- switchToSlowPath:
- onlySimpleString = 0;
- stringState = CDVJSONStringStateParsing;
- tokenBufferIdx = (atStringCharacter - stringStart) - 1L;
- if(CDVJK_EXPECT_F((tokenBufferIdx + 16UL) > parseState->token.tokenBuffer.bytes.length)) { if((tokenBuffer = cdvjk_managedBuffer_resize(&parseState->token.tokenBuffer, tokenBufferIdx + 1024UL)) == NULL) { cdvjk_error(parseState, @"Internal error: Unable to resize temporary buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = CDVJSONStringStateError; goto finishedParsing; } }
- memcpy(tokenBuffer, stringStart, tokenBufferIdx);
- goto slowMatch;
- }
-
- if(CDVJK_EXPECT_F(currentChar < 0x20UL)) { cdvjk_error(parseState, @"Invalid character < 0x20 found in string: 0x%2.2x.", currentChar); stringState = CDVJSONStringStateError; goto finishedParsing; }
-
- stringHash = cdvcalculateHash(stringHash, currentChar);
- }
- }
-
- slowMatch:
-
- for(atStringCharacter = (stringStart + ((atStringCharacter - stringStart) - 1L)); (atStringCharacter < endOfBuffer) && (tokenBufferIdx < parseState->token.tokenBuffer.bytes.length); atStringCharacter++) {
- if((tokenBufferIdx + 16UL) > parseState->token.tokenBuffer.bytes.length) { if((tokenBuffer = cdvjk_managedBuffer_resize(&parseState->token.tokenBuffer, tokenBufferIdx + 1024UL)) == NULL) { cdvjk_error(parseState, @"Internal error: Unable to resize temporary buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = CDVJSONStringStateError; goto finishedParsing; } }
-
- NSCParameterAssert(tokenBufferIdx < parseState->token.tokenBuffer.bytes.length);
-
- unsigned long currentChar = (*atStringCharacter), escapedChar;
-
- if(CDVJK_EXPECT_T(stringState == CDVJSONStringStateParsing)) {
- if(CDVJK_EXPECT_T(currentChar >= 0x20UL)) {
- if(CDVJK_EXPECT_T(currentChar < (unsigned long)0x80)) { // Not a UTF8 sequence
- if(CDVJK_EXPECT_F(currentChar == (unsigned long)'"')) { stringState = CDVJSONStringStateFinished; atStringCharacter++; goto finishedParsing; }
- if(CDVJK_EXPECT_F(currentChar == (unsigned long)'\\')) { stringState = CDVJSONStringStateEscape; continue; }
- stringHash = cdvcalculateHash(stringHash, currentChar);
- tokenBuffer[tokenBufferIdx++] = currentChar;
- continue;
- } else { // UTF8 sequence
- const unsigned char *nextValidCharacter = NULL;
- UTF32 u32ch = 0U;
- CDV_ConversionResult result;
-
- if(CDVJK_EXPECT_F((result = cdvConvertSingleCodePointInUTF8(atStringCharacter, endOfBuffer, (UTF8 const **)&nextValidCharacter, &u32ch)) != conversionOK)) {
- if((result == sourceIllegal) && ((parseState->parseOptionFlags & CDVJKParseOptionLooseUnicode) == 0)) { cdvjk_error(parseState, @"Illegal UTF8 sequence found in \"\" string."); stringState = CDVJSONStringStateError; goto finishedParsing; }
- if(result == sourceExhausted) { cdvjk_error(parseState, @"End of buffer reached while parsing UTF8 in \"\" string."); stringState = CDVJSONStringStateError; goto finishedParsing; }
- if(cdvjk_string_add_unicodeCodePoint(parseState, u32ch, &tokenBufferIdx, &stringHash)) { cdvjk_error(parseState, @"Internal error: Unable to add UTF8 sequence to internal string buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = CDVJSONStringStateError; goto finishedParsing; }
- atStringCharacter = nextValidCharacter - 1;
- continue;
- } else {
- while(atStringCharacter < nextValidCharacter) { tokenBuffer[tokenBufferIdx++] = *atStringCharacter; stringHash = cdvcalculateHash(stringHash, *atStringCharacter++); }
- atStringCharacter--;
- continue;
- }
- }
- } else { // currentChar < 0x20
- cdvjk_error(parseState, @"Invalid character < 0x20 found in string: 0x%2.2x.", currentChar); stringState = CDVJSONStringStateError; goto finishedParsing;
- }
-
- } else { // stringState != CDVJSONStringStateParsing
- int isSurrogate = 1;
-
- switch(stringState) {
- case CDVJSONStringStateEscape:
- switch(currentChar) {
- case 'u': escapedUnicode1 = 0U; escapedUnicode2 = 0U; escapedUnicodeCodePoint = 0U; stringState = CDVJSONStringStateEscapedUnicode1; break;
-
- case 'b': escapedChar = '\b'; goto parsedEscapedChar;
- case 'f': escapedChar = '\f'; goto parsedEscapedChar;
- case 'n': escapedChar = '\n'; goto parsedEscapedChar;
- case 'r': escapedChar = '\r'; goto parsedEscapedChar;
- case 't': escapedChar = '\t'; goto parsedEscapedChar;
- case '\\': escapedChar = '\\'; goto parsedEscapedChar;
- case '/': escapedChar = '/'; goto parsedEscapedChar;
- case '"': escapedChar = '"'; goto parsedEscapedChar;
-
- parsedEscapedChar:
- stringState = CDVJSONStringStateParsing;
- stringHash = cdvcalculateHash(stringHash, escapedChar);
- tokenBuffer[tokenBufferIdx++] = escapedChar;
- break;
-
- default: cdvjk_error(parseState, @"Invalid escape sequence found in \"\" string."); stringState = CDVJSONStringStateError; goto finishedParsing; break;
- }
- break;
-
- case CDVJSONStringStateEscapedUnicode1:
- case CDVJSONStringStateEscapedUnicode2:
- case CDVJSONStringStateEscapedUnicode3:
- case CDVJSONStringStateEscapedUnicode4: isSurrogate = 0;
- case CDVJSONStringStateEscapedUnicodeSurrogate1:
- case CDVJSONStringStateEscapedUnicodeSurrogate2:
- case CDVJSONStringStateEscapedUnicodeSurrogate3:
- case CDVJSONStringStateEscapedUnicodeSurrogate4:
- {
- uint16_t hexValue = 0U;
-
- switch(currentChar) {
- case '0' ... '9': hexValue = currentChar - '0'; goto parsedHex;
- case 'a' ... 'f': hexValue = (currentChar - 'a') + 10U; goto parsedHex;
- case 'A' ... 'F': hexValue = (currentChar - 'A') + 10U; goto parsedHex;
-
- parsedHex:
- if(!isSurrogate) { escapedUnicode1 = (escapedUnicode1 << 4) | hexValue; } else { escapedUnicode2 = (escapedUnicode2 << 4) | hexValue; }
-
- if(stringState == CDVJSONStringStateEscapedUnicode4) {
- if(((escapedUnicode1 >= 0xD800U) && (escapedUnicode1 < 0xE000U))) {
- if((escapedUnicode1 >= 0xD800U) && (escapedUnicode1 < 0xDC00U)) { stringState = CDVJSONStringStateEscapedNeedEscapeForSurrogate; }
- else if((escapedUnicode1 >= 0xDC00U) && (escapedUnicode1 < 0xE000U)) {
- if((parseState->parseOptionFlags & CDVJKParseOptionLooseUnicode)) { escapedUnicodeCodePoint = CDV_UNI_REPLACEMENT_CHAR; }
- else { cdvjk_error(parseState, @"Illegal \\u Unicode escape sequence."); stringState = CDVJSONStringStateError; goto finishedParsing; }
- }
- }
- else { escapedUnicodeCodePoint = escapedUnicode1; }
- }
-
- if(stringState == CDVJSONStringStateEscapedUnicodeSurrogate4) {
- if((escapedUnicode2 < 0xdc00) || (escapedUnicode2 > 0xdfff)) {
- if((parseState->parseOptionFlags & CDVJKParseOptionLooseUnicode)) { escapedUnicodeCodePoint = CDV_UNI_REPLACEMENT_CHAR; }
- else { cdvjk_error(parseState, @"Illegal \\u Unicode escape sequence."); stringState = CDVJSONStringStateError; goto finishedParsing; }
- }
- else { escapedUnicodeCodePoint = ((escapedUnicode1 - 0xd800) * 0x400) + (escapedUnicode2 - 0xdc00) + 0x10000; }
- }
-
- if((stringState == CDVJSONStringStateEscapedUnicode4) || (stringState == CDVJSONStringStateEscapedUnicodeSurrogate4)) {
- if((cdvisValidCodePoint(&escapedUnicodeCodePoint) == sourceIllegal) && ((parseState->parseOptionFlags & CDVJKParseOptionLooseUnicode) == 0)) { cdvjk_error(parseState, @"Illegal \\u Unicode escape sequence."); stringState = CDVJSONStringStateError; goto finishedParsing; }
- stringState = CDVJSONStringStateParsing;
- if(cdvjk_string_add_unicodeCodePoint(parseState, escapedUnicodeCodePoint, &tokenBufferIdx, &stringHash)) { cdvjk_error(parseState, @"Internal error: Unable to add UTF8 sequence to internal string buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = CDVJSONStringStateError; goto finishedParsing; }
- }
- else if((stringState >= CDVJSONStringStateEscapedUnicode1) && (stringState <= CDVJSONStringStateEscapedUnicodeSurrogate4)) { stringState++; }
- break;
-
- default: cdvjk_error(parseState, @"Unexpected character found in \\u Unicode escape sequence. Found '%c', expected [0-9a-fA-F].", currentChar); stringState = CDVJSONStringStateError; goto finishedParsing; break;
- }
- }
- break;
-
- case CDVJSONStringStateEscapedNeedEscapeForSurrogate:
- if(currentChar == '\\') { stringState = CDVJSONStringStateEscapedNeedEscapedUForSurrogate; }
- else {
- if((parseState->parseOptionFlags & CDVJKParseOptionLooseUnicode) == 0) { cdvjk_error(parseState, @"Required a second \\u Unicode escape sequence following a surrogate \\u Unicode escape sequence."); stringState = CDVJSONStringStateError; goto finishedParsing; }
- else { stringState = CDVJSONStringStateParsing; atStringCharacter--; if(cdvjk_string_add_unicodeCodePoint(parseState, CDV_UNI_REPLACEMENT_CHAR, &tokenBufferIdx, &stringHash)) { cdvjk_error(parseState, @"Internal error: Unable to add UTF8 sequence to internal string buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = CDVJSONStringStateError; goto finishedParsing; } }
- }
- break;
-
- case CDVJSONStringStateEscapedNeedEscapedUForSurrogate:
- if(currentChar == 'u') { stringState = CDVJSONStringStateEscapedUnicodeSurrogate1; }
- else {
- if((parseState->parseOptionFlags & CDVJKParseOptionLooseUnicode) == 0) { cdvjk_error(parseState, @"Required a second \\u Unicode escape sequence following a surrogate \\u Unicode escape sequence."); stringState = CDVJSONStringStateError; goto finishedParsing; }
- else { stringState = CDVJSONStringStateParsing; atStringCharacter -= 2; if(cdvjk_string_add_unicodeCodePoint(parseState, CDV_UNI_REPLACEMENT_CHAR, &tokenBufferIdx, &stringHash)) { cdvjk_error(parseState, @"Internal error: Unable to add UTF8 sequence to internal string buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = CDVJSONStringStateError; goto finishedParsing; } }
- }
- break;
-
- default: cdvjk_error(parseState, @"Internal error: Unknown stringState. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = CDVJSONStringStateError; goto finishedParsing; break;
- }
- }
- }
-
-finishedParsing:
-
- if(CDVJK_EXPECT_T(stringState == CDVJSONStringStateFinished)) {
- NSCParameterAssert((parseState->stringBuffer.bytes.ptr + tokenStartIndex) < atStringCharacter);
-
- parseState->token.tokenPtrRange.ptr = parseState->stringBuffer.bytes.ptr + tokenStartIndex;
- parseState->token.tokenPtrRange.length = (atStringCharacter - parseState->token.tokenPtrRange.ptr);
-
- if(CDVJK_EXPECT_T(onlySimpleString)) {
- NSCParameterAssert(((parseState->token.tokenPtrRange.ptr + 1) < endOfBuffer) && (parseState->token.tokenPtrRange.length >= 2UL) && (((parseState->token.tokenPtrRange.ptr + 1) + (parseState->token.tokenPtrRange.length - 2)) < endOfBuffer));
- parseState->token.value.ptrRange.ptr = parseState->token.tokenPtrRange.ptr + 1;
- parseState->token.value.ptrRange.length = parseState->token.tokenPtrRange.length - 2UL;
- } else {
- parseState->token.value.ptrRange.ptr = parseState->token.tokenBuffer.bytes.ptr;
- parseState->token.value.ptrRange.length = tokenBufferIdx;
- }
-
- parseState->token.value.hash = stringHash;
- parseState->token.value.type = CDVJKValueTypeString;
- parseState->atIndex = (atStringCharacter - parseState->stringBuffer.bytes.ptr);
- }
-
- if(CDVJK_EXPECT_F(stringState != CDVJSONStringStateFinished)) { cdvjk_error(parseState, @"Invalid string."); }
- return(CDVJK_EXPECT_T(stringState == CDVJSONStringStateFinished) ? 0 : 1);
-}
-
-static int cdvjk_parse_number(CDVJKParseState *parseState) {
- NSCParameterAssert((parseState != NULL) && (CDVJK_AT_STRING_PTR(parseState) <= CDVJK_END_STRING_PTR(parseState)));
- const unsigned char *numberStart = CDVJK_AT_STRING_PTR(parseState);
- const unsigned char *endOfBuffer = CDVJK_END_STRING_PTR(parseState);
- const unsigned char *atNumberCharacter = NULL;
- int numberState = CDVJSONNumberStateWholeNumberStart, isFloatingPoint = 0, isNegative = 0, backup = 0;
- size_t startingIndex = parseState->atIndex;
-
- for(atNumberCharacter = numberStart; (CDVJK_EXPECT_T(atNumberCharacter < endOfBuffer)) && (CDVJK_EXPECT_T(!(CDVJK_EXPECT_F(numberState == CDVJSONNumberStateFinished) || CDVJK_EXPECT_F(numberState == CDVJSONNumberStateError)))); atNumberCharacter++) {
- unsigned long currentChar = (unsigned long)(*atNumberCharacter), lowerCaseCC = currentChar | 0x20UL;
-
- switch(numberState) {
- case CDVJSONNumberStateWholeNumberStart: if (currentChar == '-') { numberState = CDVJSONNumberStateWholeNumberMinus; isNegative = 1; break; }
- case CDVJSONNumberStateWholeNumberMinus: if (currentChar == '0') { numberState = CDVJSONNumberStateWholeNumberZero; break; }
- else if( (currentChar >= '1') && (currentChar <= '9')) { numberState = CDVJSONNumberStateWholeNumber; break; }
- else { /* XXX Add error message */ numberState = CDVJSONNumberStateError; break; }
- case CDVJSONNumberStateExponentStart: if( (currentChar == '+') || (currentChar == '-')) { numberState = CDVJSONNumberStateExponentPlusMinus; break; }
- case CDVJSONNumberStateFractionalNumberStart:
- case CDVJSONNumberStateExponentPlusMinus:if(!((currentChar >= '0') && (currentChar <= '9'))) { /* XXX Add error message */ numberState = CDVJSONNumberStateError; break; }
- else { if(numberState == CDVJSONNumberStateFractionalNumberStart) { numberState = CDVJSONNumberStateFractionalNumber; }
- else { numberState = CDVJSONNumberStateExponent; } break; }
- case CDVJSONNumberStateWholeNumberZero:
- case CDVJSONNumberStateWholeNumber: if (currentChar == '.') { numberState = CDVJSONNumberStateFractionalNumberStart; isFloatingPoint = 1; break; }
- case CDVJSONNumberStateFractionalNumber: if (lowerCaseCC == 'e') { numberState = CDVJSONNumberStateExponentStart; isFloatingPoint = 1; break; }
- case CDVJSONNumberStateExponent: if(!((currentChar >= '0') && (currentChar <= '9')) || (numberState == CDVJSONNumberStateWholeNumberZero)) { numberState = CDVJSONNumberStateFinished; backup = 1; break; }
- break;
- default: /* XXX Add error message */ numberState = CDVJSONNumberStateError; break;
- }
- }
-
- parseState->token.tokenPtrRange.ptr = parseState->stringBuffer.bytes.ptr + startingIndex;
- parseState->token.tokenPtrRange.length = (atNumberCharacter - parseState->token.tokenPtrRange.ptr) - backup;
- parseState->atIndex = (parseState->token.tokenPtrRange.ptr + parseState->token.tokenPtrRange.length) - parseState->stringBuffer.bytes.ptr;
-
- if(CDVJK_EXPECT_T(numberState == CDVJSONNumberStateFinished)) {
- unsigned char numberTempBuf[parseState->token.tokenPtrRange.length + 4UL];
- unsigned char *endOfNumber = NULL;
-
- memcpy(numberTempBuf, parseState->token.tokenPtrRange.ptr, parseState->token.tokenPtrRange.length);
- numberTempBuf[parseState->token.tokenPtrRange.length] = 0;
-
- errno = 0;
-
- // Treat "-0" as a floating point number, which is capable of representing negative zeros.
- if(CDVJK_EXPECT_F(parseState->token.tokenPtrRange.length == 2UL) && CDVJK_EXPECT_F(numberTempBuf[1] == '0') && CDVJK_EXPECT_F(isNegative)) { isFloatingPoint = 1; }
-
- if(isFloatingPoint) {
- parseState->token.value.number.doubleValue = strtod((const char *)numberTempBuf, (char **)&endOfNumber); // strtod is documented to return U+2261 (identical to) 0.0 on an underflow error (along with setting errno to ERANGE).
- parseState->token.value.type = CDVJKValueTypeDouble;
- parseState->token.value.ptrRange.ptr = (const unsigned char *)&parseState->token.value.number.doubleValue;
- parseState->token.value.ptrRange.length = sizeof(double);
- parseState->token.value.hash = (CDVJK_HASH_INIT + parseState->token.value.type);
- } else {
- if(isNegative) {
- parseState->token.value.number.longLongValue = strtoll((const char *)numberTempBuf, (char **)&endOfNumber, 10);
- parseState->token.value.type = CDVJKValueTypeLongLong;
- parseState->token.value.ptrRange.ptr = (const unsigned char *)&parseState->token.value.number.longLongValue;
- parseState->token.value.ptrRange.length = sizeof(long long);
- parseState->token.value.hash = (CDVJK_HASH_INIT + parseState->token.value.type) + (CDVJKHash)parseState->token.value.number.longLongValue;
- } else {
- parseState->token.value.number.unsignedLongLongValue = strtoull((const char *)numberTempBuf, (char **)&endOfNumber, 10);
- parseState->token.value.type = CDVJKValueTypeUnsignedLongLong;
- parseState->token.value.ptrRange.ptr = (const unsigned char *)&parseState->token.value.number.unsignedLongLongValue;
- parseState->token.value.ptrRange.length = sizeof(unsigned long long);
- parseState->token.value.hash = (CDVJK_HASH_INIT + parseState->token.value.type) + (CDVJKHash)parseState->token.value.number.unsignedLongLongValue;
- }
- }
-
- if(CDVJK_EXPECT_F(errno != 0)) {
- numberState = CDVJSONNumberStateError;
- if(errno == ERANGE) {
- switch(parseState->token.value.type) {
- case CDVJKValueTypeDouble: cdvjk_error(parseState, @"The value '%s' could not be represented as a 'double' due to %s.", numberTempBuf, (parseState->token.value.number.doubleValue == 0.0) ? "underflow" : "overflow"); break; // see above for == 0.0.
- case CDVJKValueTypeLongLong: cdvjk_error(parseState, @"The value '%s' exceeded the minimum value that could be represented: %lld.", numberTempBuf, parseState->token.value.number.longLongValue); break;
- case CDVJKValueTypeUnsignedLongLong: cdvjk_error(parseState, @"The value '%s' exceeded the maximum value that could be represented: %llu.", numberTempBuf, parseState->token.value.number.unsignedLongLongValue); break;
- default: cdvjk_error(parseState, @"Internal error: Unknown token value type. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); break;
- }
- }
- }
- if(CDVJK_EXPECT_F(endOfNumber != &numberTempBuf[parseState->token.tokenPtrRange.length]) && CDVJK_EXPECT_F(numberState != CDVJSONNumberStateError)) { numberState = CDVJSONNumberStateError; cdvjk_error(parseState, @"The conversion function did not consume all of the number tokens characters."); }
-
- size_t hashIndex = 0UL;
- for(hashIndex = 0UL; hashIndex < parseState->token.value.ptrRange.length; hashIndex++) { parseState->token.value.hash = cdvcalculateHash(parseState->token.value.hash, parseState->token.value.ptrRange.ptr[hashIndex]); }
- }
-
- if(CDVJK_EXPECT_F(numberState != CDVJSONNumberStateFinished)) { cdvjk_error(parseState, @"Invalid number."); }
- return(CDVJK_EXPECT_T((numberState == CDVJSONNumberStateFinished)) ? 0 : 1);
-}
-
-CDVJK_STATIC_INLINE void cdvjk_set_parsed_token(CDVJKParseState *parseState, const unsigned char *ptr, size_t length, CDVJKTokenType type, size_t advanceBy) {
- parseState->token.tokenPtrRange.ptr = ptr;
- parseState->token.tokenPtrRange.length = length;
- parseState->token.type = type;
- parseState->atIndex += advanceBy;
-}
-
-static size_t cdvjk_parse_is_newline(CDVJKParseState *parseState, const unsigned char *atCharacterPtr) {
- NSCParameterAssert((parseState != NULL) && (atCharacterPtr != NULL) && (atCharacterPtr >= parseState->stringBuffer.bytes.ptr) && (atCharacterPtr < CDVJK_END_STRING_PTR(parseState)));
- const unsigned char *endOfStringPtr = CDVJK_END_STRING_PTR(parseState);
-
- if(CDVJK_EXPECT_F(atCharacterPtr >= endOfStringPtr)) { return(0UL); }
-
- if(CDVJK_EXPECT_F((*(atCharacterPtr + 0)) == '\n')) { return(1UL); }
- if(CDVJK_EXPECT_F((*(atCharacterPtr + 0)) == '\r')) { if((CDVJK_EXPECT_T((atCharacterPtr + 1) < endOfStringPtr)) && ((*(atCharacterPtr + 1)) == '\n')) { return(2UL); } return(1UL); }
- if(parseState->parseOptionFlags & CDVJKParseOptionUnicodeNewlines) {
- if((CDVJK_EXPECT_F((*(atCharacterPtr + 0)) == 0xc2)) && (((atCharacterPtr + 1) < endOfStringPtr) && ((*(atCharacterPtr + 1)) == 0x85))) { return(2UL); }
- if((CDVJK_EXPECT_F((*(atCharacterPtr + 0)) == 0xe2)) && (((atCharacterPtr + 2) < endOfStringPtr) && ((*(atCharacterPtr + 1)) == 0x80) && (((*(atCharacterPtr + 2)) == 0xa8) || ((*(atCharacterPtr + 2)) == 0xa9)))) { return(3UL); }
- }
-
- return(0UL);
-}
-
-CDVJK_STATIC_INLINE int cdvjk_parse_skip_newline(CDVJKParseState *parseState) {
- size_t newlineAdvanceAtIndex = 0UL;
- if(CDVJK_EXPECT_F((newlineAdvanceAtIndex = cdvjk_parse_is_newline(parseState, CDVJK_AT_STRING_PTR(parseState))) > 0UL)) { parseState->lineNumber++; parseState->atIndex += (newlineAdvanceAtIndex - 1UL); parseState->lineStartIndex = parseState->atIndex + 1UL; return(1); }
- return(0);
-}
-
-CDVJK_STATIC_INLINE void cdvjk_parse_skip_whitespace(CDVJKParseState *parseState) {
-#ifndef __clang_analyzer__
- NSCParameterAssert((parseState != NULL) && (CDVJK_AT_STRING_PTR(parseState) <= CDVJK_END_STRING_PTR(parseState)));
- const unsigned char *atCharacterPtr = NULL;
- const unsigned char *endOfStringPtr = CDVJK_END_STRING_PTR(parseState);
-
- for(atCharacterPtr = CDVJK_AT_STRING_PTR(parseState); (CDVJK_EXPECT_T((atCharacterPtr = CDVJK_AT_STRING_PTR(parseState)) < endOfStringPtr)); parseState->atIndex++) {
- if(((*(atCharacterPtr + 0)) == ' ') || ((*(atCharacterPtr + 0)) == '\t')) { continue; }
- if(cdvjk_parse_skip_newline(parseState)) { continue; }
- if(parseState->parseOptionFlags & CDVJKParseOptionComments) {
- if((CDVJK_EXPECT_F((*(atCharacterPtr + 0)) == '/')) && (CDVJK_EXPECT_T((atCharacterPtr + 1) < endOfStringPtr))) {
- if((*(atCharacterPtr + 1)) == '/') {
- parseState->atIndex++;
- for(atCharacterPtr = CDVJK_AT_STRING_PTR(parseState); (CDVJK_EXPECT_T((atCharacterPtr = CDVJK_AT_STRING_PTR(parseState)) < endOfStringPtr)); parseState->atIndex++) { if(cdvjk_parse_skip_newline(parseState)) { break; } }
- continue;
- }
- if((*(atCharacterPtr + 1)) == '*') {
- parseState->atIndex++;
- for(atCharacterPtr = CDVJK_AT_STRING_PTR(parseState); (CDVJK_EXPECT_T((atCharacterPtr = CDVJK_AT_STRING_PTR(parseState)) < endOfStringPtr)); parseState->atIndex++) {
- if(cdvjk_parse_skip_newline(parseState)) { continue; }
- if(((*(atCharacterPtr + 0)) == '*') && (((atCharacterPtr + 1) < endOfStringPtr) && ((*(atCharacterPtr + 1)) == '/'))) { parseState->atIndex++; break; }
- }
- continue;
- }
- }
- }
- break;
- }
-#endif
-}
-
-static int cdvjk_parse_next_token(CDVJKParseState *parseState) {
- NSCParameterAssert((parseState != NULL) && (CDVJK_AT_STRING_PTR(parseState) <= CDVJK_END_STRING_PTR(parseState)));
- const unsigned char *atCharacterPtr = NULL;
- const unsigned char *endOfStringPtr = CDVJK_END_STRING_PTR(parseState);
- unsigned char currentCharacter = 0U;
- int stopParsing = 0;
-
- parseState->prev_atIndex = parseState->atIndex;
- parseState->prev_lineNumber = parseState->lineNumber;
- parseState->prev_lineStartIndex = parseState->lineStartIndex;
-
- cdvjk_parse_skip_whitespace(parseState);
-
- if((CDVJK_AT_STRING_PTR(parseState) == endOfStringPtr)) { stopParsing = 1; }
-
- if((CDVJK_EXPECT_T(stopParsing == 0)) && (CDVJK_EXPECT_T((atCharacterPtr = CDVJK_AT_STRING_PTR(parseState)) < endOfStringPtr))) {
- currentCharacter = *atCharacterPtr;
-
- if(CDVJK_EXPECT_T(currentCharacter == '"')) { if(CDVJK_EXPECT_T((stopParsing = cdvjk_parse_string(parseState)) == 0)) { cdvjk_set_parsed_token(parseState, parseState->token.tokenPtrRange.ptr, parseState->token.tokenPtrRange.length, CDVJKTokenTypeString, 0UL); } }
- else if(CDVJK_EXPECT_T(currentCharacter == ':')) { cdvjk_set_parsed_token(parseState, atCharacterPtr, 1UL, CDVJKTokenTypeSeparator, 1UL); }
- else if(CDVJK_EXPECT_T(currentCharacter == ',')) { cdvjk_set_parsed_token(parseState, atCharacterPtr, 1UL, CDVJKTokenTypeComma, 1UL); }
- else if((CDVJK_EXPECT_T(currentCharacter >= '0') && CDVJK_EXPECT_T(currentCharacter <= '9')) || CDVJK_EXPECT_T(currentCharacter == '-')) { if(CDVJK_EXPECT_T((stopParsing = cdvjk_parse_number(parseState)) == 0)) { cdvjk_set_parsed_token(parseState, parseState->token.tokenPtrRange.ptr, parseState->token.tokenPtrRange.length, CDVJKTokenTypeNumber, 0UL); } }
- else if(CDVJK_EXPECT_T(currentCharacter == '{')) { cdvjk_set_parsed_token(parseState, atCharacterPtr, 1UL, CDVJKTokenTypeObjectBegin, 1UL); }
- else if(CDVJK_EXPECT_T(currentCharacter == '}')) { cdvjk_set_parsed_token(parseState, atCharacterPtr, 1UL, CDVJKTokenTypeObjectEnd, 1UL); }
- else if(CDVJK_EXPECT_T(currentCharacter == '[')) { cdvjk_set_parsed_token(parseState, atCharacterPtr, 1UL, CDVJKTokenTypeArrayBegin, 1UL); }
- else if(CDVJK_EXPECT_T(currentCharacter == ']')) { cdvjk_set_parsed_token(parseState, atCharacterPtr, 1UL, CDVJKTokenTypeArrayEnd, 1UL); }
-
- else if(CDVJK_EXPECT_T(currentCharacter == 't')) { if(!((CDVJK_EXPECT_T((atCharacterPtr + 4UL) < endOfStringPtr)) && (CDVJK_EXPECT_T(atCharacterPtr[1] == 'r')) && (CDVJK_EXPECT_T(atCharacterPtr[2] == 'u')) && (CDVJK_EXPECT_T(atCharacterPtr[3] == 'e')))) { stopParsing = 1; /* XXX Add error message */ } else { cdvjk_set_parsed_token(parseState, atCharacterPtr, 4UL, CDVJKTokenTypeTrue, 4UL); } }
- else if(CDVJK_EXPECT_T(currentCharacter == 'f')) { if(!((CDVJK_EXPECT_T((atCharacterPtr + 5UL) < endOfStringPtr)) && (CDVJK_EXPECT_T(atCharacterPtr[1] == 'a')) && (CDVJK_EXPECT_T(atCharacterPtr[2] == 'l')) && (CDVJK_EXPECT_T(atCharacterPtr[3] == 's')) && (CDVJK_EXPECT_T(atCharacterPtr[4] == 'e')))) { stopParsing = 1; /* XXX Add error message */ } else { cdvjk_set_parsed_token(parseState, atCharacterPtr, 5UL, CDVJKTokenTypeFalse, 5UL); } }
- else if(CDVJK_EXPECT_T(currentCharacter == 'n')) { if(!((CDVJK_EXPECT_T((atCharacterPtr + 4UL) < endOfStringPtr)) && (CDVJK_EXPECT_T(atCharacterPtr[1] == 'u')) && (CDVJK_EXPECT_T(atCharacterPtr[2] == 'l')) && (CDVJK_EXPECT_T(atCharacterPtr[3] == 'l')))) { stopParsing = 1; /* XXX Add error message */ } else { cdvjk_set_parsed_token(parseState, atCharacterPtr, 4UL, CDVJKTokenTypeNull, 4UL); } }
- else { stopParsing = 1; /* XXX Add error message */ }
- }
-
- if(CDVJK_EXPECT_F(stopParsing)) { cdvjk_error(parseState, @"Unexpected token, wanted '{', '}', '[', ']', ',', ':', 'true', 'false', 'null', '\"STRING\"', 'NUMBER'."); }
- return(stopParsing);
-}
-
-static void cdvjk_error_parse_accept_or3(CDVJKParseState *parseState, int state, NSString *or1String, NSString *or2String, NSString *or3String) {
- NSString *acceptStrings[16];
- int acceptIdx = 0;
- if(state & CDVJKParseAcceptValue) { acceptStrings[acceptIdx++] = or1String; }
- if(state & CDVJKParseAcceptComma) { acceptStrings[acceptIdx++] = or2String; }
- if(state & CDVJKParseAcceptEnd) { acceptStrings[acceptIdx++] = or3String; }
- if(acceptIdx == 1) { cdvjk_error(parseState, @"Expected %@, not '%*.*s'", acceptStrings[0], (int)parseState->token.tokenPtrRange.length, (int)parseState->token.tokenPtrRange.length, parseState->token.tokenPtrRange.ptr); }
- else if(acceptIdx == 2) { cdvjk_error(parseState, @"Expected %@ or %@, not '%*.*s'", acceptStrings[0], acceptStrings[1], (int)parseState->token.tokenPtrRange.length, (int)parseState->token.tokenPtrRange.length, parseState->token.tokenPtrRange.ptr); }
- else if(acceptIdx == 3) { cdvjk_error(parseState, @"Expected %@, %@, or %@, not '%*.*s", acceptStrings[0], acceptStrings[1], acceptStrings[2], (int)parseState->token.tokenPtrRange.length, (int)parseState->token.tokenPtrRange.length, parseState->token.tokenPtrRange.ptr); }
-}
-
-static void *cdvjk_parse_array(CDVJKParseState *parseState) {
- size_t startingObjectIndex = parseState->objectStack.index;
- int arrayState = CDVJKParseAcceptValueOrEnd, stopParsing = 0;
- void *parsedArray = NULL;
-
- while(CDVJK_EXPECT_T((CDVJK_EXPECT_T(stopParsing == 0)) && (CDVJK_EXPECT_T(parseState->atIndex < parseState->stringBuffer.bytes.length)))) {
- if(CDVJK_EXPECT_F(parseState->objectStack.index > (parseState->objectStack.count - 4UL))) { if(cdvjk_objectStack_resize(&parseState->objectStack, parseState->objectStack.count + 128UL)) { cdvjk_error(parseState, @"Internal error: [array] objectsIndex > %zu, resize failed? %@ line %#ld", (parseState->objectStack.count - 4UL), [NSString stringWithUTF8String:__FILE__], (long)__LINE__); break; } }
-
- if(CDVJK_EXPECT_T((stopParsing = cdvjk_parse_next_token(parseState)) == 0)) {
- void *object = NULL;
-#ifndef NS_BLOCK_ASSERTIONS
- parseState->objectStack.objects[parseState->objectStack.index] = NULL;
- parseState->objectStack.keys [parseState->objectStack.index] = NULL;
-#endif
- switch(parseState->token.type) {
- case CDVJKTokenTypeNumber:
- case CDVJKTokenTypeString:
- case CDVJKTokenTypeTrue:
- case CDVJKTokenTypeFalse:
- case CDVJKTokenTypeNull:
- case CDVJKTokenTypeArrayBegin:
- case CDVJKTokenTypeObjectBegin:
- if(CDVJK_EXPECT_F((arrayState & CDVJKParseAcceptValue) == 0)) { parseState->errorIsPrev = 1; cdvjk_error(parseState, @"Unexpected value."); stopParsing = 1; break; }
- if(CDVJK_EXPECT_F((object = cdvjk_object_for_token(parseState)) == NULL)) { cdvjk_error(parseState, @"Internal error: Object == NULL"); stopParsing = 1; break; } else { parseState->objectStack.objects[parseState->objectStack.index++] = object; arrayState = CDVJKParseAcceptCommaOrEnd; }
- break;
- case CDVJKTokenTypeArrayEnd: if(CDVJK_EXPECT_T(arrayState & CDVJKParseAcceptEnd)) { NSCParameterAssert(parseState->objectStack.index >= startingObjectIndex); parsedArray = (void *)_CDVJKArrayCreate((id *)&parseState->objectStack.objects[startingObjectIndex], (parseState->objectStack.index - startingObjectIndex), parseState->mutableCollections); } else { parseState->errorIsPrev = 1; cdvjk_error(parseState, @"Unexpected ']'."); } stopParsing = 1; break;
- case CDVJKTokenTypeComma: if(CDVJK_EXPECT_T(arrayState & CDVJKParseAcceptComma)) { arrayState = CDVJKParseAcceptValue; } else { parseState->errorIsPrev = 1; cdvjk_error(parseState, @"Unexpected ','."); stopParsing = 1; } break;
- default: parseState->errorIsPrev = 1; cdvjk_error_parse_accept_or3(parseState, arrayState, @"a value", @"a comma", @"a ']'"); stopParsing = 1; break;
- }
- }
- }
-
- if(CDVJK_EXPECT_F(parsedArray == NULL)) { size_t idx = 0UL; for(idx = startingObjectIndex; idx < parseState->objectStack.index; idx++) { if(parseState->objectStack.objects[idx] != NULL) { CFRelease(parseState->objectStack.objects[idx]); parseState->objectStack.objects[idx] = NULL; } } }
-#if !defined(NS_BLOCK_ASSERTIONS)
- else { size_t idx = 0UL; for(idx = startingObjectIndex; idx < parseState->objectStack.index; idx++) { parseState->objectStack.objects[idx] = NULL; parseState->objectStack.keys[idx] = NULL; } }
-#endif
-
- parseState->objectStack.index = startingObjectIndex;
- return(parsedArray);
-}
-
-static void *cdvjk_create_dictionary(CDVJKParseState *parseState, size_t startingObjectIndex) {
- void *parsedDictionary = NULL;
-
- parseState->objectStack.index--;
-
- parsedDictionary = _CDVJKDictionaryCreate((id *)&parseState->objectStack.keys[startingObjectIndex], (NSUInteger *)&parseState->objectStack.cfHashes[startingObjectIndex], (id *)&parseState->objectStack.objects[startingObjectIndex], (parseState->objectStack.index - startingObjectIndex), parseState->mutableCollections);
-
- return(parsedDictionary);
-}
-
-static void *cdvjk_parse_dictionary(CDVJKParseState *parseState) {
- size_t startingObjectIndex = parseState->objectStack.index;
- int dictState = CDVJKParseAcceptValueOrEnd, stopParsing = 0;
- void *parsedDictionary = NULL;
-
- while(CDVJK_EXPECT_T((CDVJK_EXPECT_T(stopParsing == 0)) && (CDVJK_EXPECT_T(parseState->atIndex < parseState->stringBuffer.bytes.length)))) {
- if(CDVJK_EXPECT_F(parseState->objectStack.index > (parseState->objectStack.count - 4UL))) { if(cdvjk_objectStack_resize(&parseState->objectStack, parseState->objectStack.count + 128UL)) { cdvjk_error(parseState, @"Internal error: [dictionary] objectsIndex > %zu, resize failed? %@ line #%ld", (parseState->objectStack.count - 4UL), [NSString stringWithUTF8String:__FILE__], (long)__LINE__); break; } }
-
- size_t objectStackIndex = parseState->objectStack.index++;
- parseState->objectStack.keys[objectStackIndex] = NULL;
- parseState->objectStack.objects[objectStackIndex] = NULL;
- void *key = NULL, *object = NULL;
-
- if(CDVJK_EXPECT_T((CDVJK_EXPECT_T(stopParsing == 0)) && (CDVJK_EXPECT_T((stopParsing = cdvjk_parse_next_token(parseState)) == 0)))) {
- switch(parseState->token.type) {
- case CDVJKTokenTypeString:
- if(CDVJK_EXPECT_F((dictState & CDVJKParseAcceptValue) == 0)) { parseState->errorIsPrev = 1; cdvjk_error(parseState, @"Unexpected string."); stopParsing = 1; break; }
- if(CDVJK_EXPECT_F((key = cdvjk_object_for_token(parseState)) == NULL)) { cdvjk_error(parseState, @"Internal error: Key == NULL."); stopParsing = 1; break; }
- else {
- parseState->objectStack.keys[objectStackIndex] = key;
- if(CDVJK_EXPECT_T(parseState->token.value.cacheItem != NULL)) { if(CDVJK_EXPECT_F(parseState->token.value.cacheItem->cfHash == 0UL)) { parseState->token.value.cacheItem->cfHash = CFHash(key); } parseState->objectStack.cfHashes[objectStackIndex] = parseState->token.value.cacheItem->cfHash; }
- else { parseState->objectStack.cfHashes[objectStackIndex] = CFHash(key); }
- }
- break;
-
- case CDVJKTokenTypeObjectEnd: if((CDVJK_EXPECT_T(dictState & CDVJKParseAcceptEnd))) { NSCParameterAssert(parseState->objectStack.index >= startingObjectIndex); parsedDictionary = cdvjk_create_dictionary(parseState, startingObjectIndex); } else { parseState->errorIsPrev = 1; cdvjk_error(parseState, @"Unexpected '}'."); } stopParsing = 1; break;
- case CDVJKTokenTypeComma: if((CDVJK_EXPECT_T(dictState & CDVJKParseAcceptComma))) { dictState = CDVJKParseAcceptValue; parseState->objectStack.index--; continue; } else { parseState->errorIsPrev = 1; cdvjk_error(parseState, @"Unexpected ','."); stopParsing = 1; } break;
-
- default: parseState->errorIsPrev = 1; cdvjk_error_parse_accept_or3(parseState, dictState, @"a \"STRING\"", @"a comma", @"a '}'"); stopParsing = 1; break;
- }
- }
-
- if(CDVJK_EXPECT_T(stopParsing == 0)) {
- if(CDVJK_EXPECT_T((stopParsing = cdvjk_parse_next_token(parseState)) == 0)) { if(CDVJK_EXPECT_F(parseState->token.type != CDVJKTokenTypeSeparator)) { parseState->errorIsPrev = 1; cdvjk_error(parseState, @"Expected ':'."); stopParsing = 1; } }
- }
-
- if((CDVJK_EXPECT_T(stopParsing == 0)) && (CDVJK_EXPECT_T((stopParsing = cdvjk_parse_next_token(parseState)) == 0))) {
- switch(parseState->token.type) {
- case CDVJKTokenTypeNumber:
- case CDVJKTokenTypeString:
- case CDVJKTokenTypeTrue:
- case CDVJKTokenTypeFalse:
- case CDVJKTokenTypeNull:
- case CDVJKTokenTypeArrayBegin:
- case CDVJKTokenTypeObjectBegin:
- if(CDVJK_EXPECT_F((dictState & CDVJKParseAcceptValue) == 0)) { parseState->errorIsPrev = 1; cdvjk_error(parseState, @"Unexpected value."); stopParsing = 1; break; }
- if(CDVJK_EXPECT_F((object = cdvjk_object_for_token(parseState)) == NULL)) { cdvjk_error(parseState, @"Internal error: Object == NULL."); stopParsing = 1; break; } else { parseState->objectStack.objects[objectStackIndex] = object; dictState = CDVJKParseAcceptCommaOrEnd; }
- break;
- default: parseState->errorIsPrev = 1; cdvjk_error_parse_accept_or3(parseState, dictState, @"a value", @"a comma", @"a '}'"); stopParsing = 1; break;
- }
- }
- }
-
- if(CDVJK_EXPECT_F(parsedDictionary == NULL)) { size_t idx = 0UL; for(idx = startingObjectIndex; idx < parseState->objectStack.index; idx++) { if(parseState->objectStack.keys[idx] != NULL) { CFRelease(parseState->objectStack.keys[idx]); parseState->objectStack.keys[idx] = NULL; } if(parseState->objectStack.objects[idx] != NULL) { CFRelease(parseState->objectStack.objects[idx]); parseState->objectStack.objects[idx] = NULL; } } }
-#if !defined(NS_BLOCK_ASSERTIONS)
- else { size_t idx = 0UL; for(idx = startingObjectIndex; idx < parseState->objectStack.index; idx++) { parseState->objectStack.objects[idx] = NULL; parseState->objectStack.keys[idx] = NULL; } }
-#endif
-
- parseState->objectStack.index = startingObjectIndex;
- return(parsedDictionary);
-}
-
-static id json_parse_it(CDVJKParseState *parseState) {
- id parsedObject = NULL;
- int stopParsing = 0;
-
- while((CDVJK_EXPECT_T(stopParsing == 0)) && (CDVJK_EXPECT_T(parseState->atIndex < parseState->stringBuffer.bytes.length))) {
- if((CDVJK_EXPECT_T(stopParsing == 0)) && (CDVJK_EXPECT_T((stopParsing = cdvjk_parse_next_token(parseState)) == 0))) {
- switch(parseState->token.type) {
- case CDVJKTokenTypeArrayBegin:
- case CDVJKTokenTypeObjectBegin: parsedObject = [(id)cdvjk_object_for_token(parseState) autorelease]; stopParsing = 1; break;
- default: cdvjk_error(parseState, @"Expected either '[' or '{'."); stopParsing = 1; break;
- }
- }
- }
-
- NSCParameterAssert((parseState->objectStack.index == 0) && (CDVJK_AT_STRING_PTR(parseState) <= CDVJK_END_STRING_PTR(parseState)));
-
- if((parsedObject == NULL) && (CDVJK_AT_STRING_PTR(parseState) == CDVJK_END_STRING_PTR(parseState))) { cdvjk_error(parseState, @"Reached the end of the buffer."); }
- if(parsedObject == NULL) { cdvjk_error(parseState, @"Unable to parse CDVJSON."); }
-
- if((parsedObject != NULL) && (CDVJK_AT_STRING_PTR(parseState) < CDVJK_END_STRING_PTR(parseState))) {
- cdvjk_parse_skip_whitespace(parseState);
- if((parsedObject != NULL) && ((parseState->parseOptionFlags & CDVJKParseOptionPermitTextAfterValidJSON) == 0) && (CDVJK_AT_STRING_PTR(parseState) < CDVJK_END_STRING_PTR(parseState))) {
- cdvjk_error(parseState, @"A valid CDVJSON object was parsed but there were additional non-white-space characters remaining.");
- parsedObject = NULL;
- }
- }
-
- return(parsedObject);
-}
-
-////////////
-#pragma mark -
-#pragma mark Object cache
-
-// This uses a Galois Linear Feedback Shift Register (LFSR) PRNG to pick which item in the cache to age. It has a period of (2^32)-1.
-// NOTE: A LFSR *MUST* be initialized to a non-zero value and must always have a non-zero value.
-CDVJK_STATIC_INLINE void cdvjk_cache_age(CDVJKParseState *parseState) {
- NSCParameterAssert((parseState != NULL) && (parseState->cache.prng_lfsr != 0U));
- parseState->cache.prng_lfsr = (parseState->cache.prng_lfsr >> 1) ^ ((0U - (parseState->cache.prng_lfsr & 1U)) & 0x80200003U);
- parseState->cache.age[parseState->cache.prng_lfsr & (parseState->cache.count - 1UL)] >>= 1;
-}
-
-// The object cache is nothing more than a hash table with open addressing collision resolution that is bounded by CDVJK_CACHE_PROBES attempts.
-//
-// The hash table is a linear C array of CDVJKTokenCacheItem. The terms "item" and "bucket" are synonymous with the index in to the cache array, i.e. cache.items[bucket].
-//
-// Items in the cache have an age associated with them. The age is the number of rightmost 1 bits, i.e. 0000 = 0, 0001 = 1, 0011 = 2, 0111 = 3, 1111 = 4.
-// This allows us to use left and right shifts to add or subtract from an items age. Add = (age << 1) | 1. Subtract = age >> 0. Subtract is synonymous with "age" (i.e., age an item).
-// The reason for this is it allows us to perform saturated adds and subtractions and is branchless.
-// The primitive C type MUST be unsigned. It is currently a "char", which allows (at a minimum and in practice) 8 bits.
-//
-// A "useable bucket" is a bucket that is not in use (never populated), or has an age == 0.
-//
-// When an item is found in the cache, it's age is incremented.
-// If a useable bucket hasn't been found, the current item (bucket) is aged along with two random items.
-//
-// If a value is not found in the cache, and no useable bucket has been found, that value is not added to the cache.
-
-static void *cdvjk_cachedObjects(CDVJKParseState *parseState) {
- unsigned long bucket = parseState->token.value.hash & (parseState->cache.count - 1UL), setBucket = 0UL, useableBucket = 0UL, x = 0UL;
- void *parsedAtom = NULL;
-
- if(CDVJK_EXPECT_F(parseState->token.value.ptrRange.length == 0UL) && CDVJK_EXPECT_T(parseState->token.value.type == CDVJKValueTypeString)) { return(@""); }
-
- for(x = 0UL; x < CDVJK_CACHE_PROBES; x++) {
- if(CDVJK_EXPECT_F(parseState->cache.items[bucket].object == NULL)) { setBucket = 1UL; useableBucket = bucket; break; }
-
- if((CDVJK_EXPECT_T(parseState->cache.items[bucket].hash == parseState->token.value.hash)) && (CDVJK_EXPECT_T(parseState->cache.items[bucket].size == parseState->token.value.ptrRange.length)) && (CDVJK_EXPECT_T(parseState->cache.items[bucket].type == parseState->token.value.type)) && (CDVJK_EXPECT_T(parseState->cache.items[bucket].bytes != NULL)) && (CDVJK_EXPECT_T(memcmp(parseState->cache.items[bucket].bytes, parseState->token.value.ptrRange.ptr, parseState->token.value.ptrRange.length) == 0U))) {
- parseState->cache.age[bucket] = (parseState->cache.age[bucket] << 1) | 1U;
- parseState->token.value.cacheItem = &parseState->cache.items[bucket];
- NSCParameterAssert(parseState->cache.items[bucket].object != NULL);
- return((void *)CFRetain(parseState->cache.items[bucket].object));
- } else {
- if(CDVJK_EXPECT_F(setBucket == 0UL) && CDVJK_EXPECT_F(parseState->cache.age[bucket] == 0U)) { setBucket = 1UL; useableBucket = bucket; }
- if(CDVJK_EXPECT_F(setBucket == 0UL)) { parseState->cache.age[bucket] >>= 1; cdvjk_cache_age(parseState); cdvjk_cache_age(parseState); }
- // This is the open addressing function. The values length and type are used as a form of "double hashing" to distribute values with the same effective value hash across different object cache buckets.
- // The values type is a prime number that is relatively coprime to the other primes in the set of value types and the number of hash table buckets.
- bucket = (parseState->token.value.hash + (parseState->token.value.ptrRange.length * (x + 1UL)) + (parseState->token.value.type * (x + 1UL)) + (3UL * (x + 1UL))) & (parseState->cache.count - 1UL);
- }
- }
-
- switch(parseState->token.value.type) {
- case CDVJKValueTypeString: parsedAtom = (void *)CFStringCreateWithBytes(NULL, parseState->token.value.ptrRange.ptr, parseState->token.value.ptrRange.length, kCFStringEncodingUTF8, 0); break;
- case CDVJKValueTypeLongLong: parsedAtom = (void *)CFNumberCreate(NULL, kCFNumberLongLongType, &parseState->token.value.number.longLongValue); break;
- case CDVJKValueTypeUnsignedLongLong:
- if(parseState->token.value.number.unsignedLongLongValue <= LLONG_MAX) { parsedAtom = (void *)CFNumberCreate(NULL, kCFNumberLongLongType, &parseState->token.value.number.unsignedLongLongValue); }
- else { parsedAtom = (void *)parseState->objCImpCache.NSNumberInitWithUnsignedLongLong(parseState->objCImpCache.NSNumberAlloc(parseState->objCImpCache.NSNumberClass, @selector(alloc)), @selector(initWithUnsignedLongLong:), parseState->token.value.number.unsignedLongLongValue); }
- break;
- case CDVJKValueTypeDouble: parsedAtom = (void *)CFNumberCreate(NULL, kCFNumberDoubleType, &parseState->token.value.number.doubleValue); break;
- default: cdvjk_error(parseState, @"Internal error: Unknown token value type. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); break;
- }
-
- if(CDVJK_EXPECT_T(setBucket) && (CDVJK_EXPECT_T(parsedAtom != NULL))) {
- bucket = useableBucket;
- if(CDVJK_EXPECT_T((parseState->cache.items[bucket].object != NULL))) { CFRelease(parseState->cache.items[bucket].object); parseState->cache.items[bucket].object = NULL; }
-
- if(CDVJK_EXPECT_T((parseState->cache.items[bucket].bytes = (unsigned char *)reallocf(parseState->cache.items[bucket].bytes, parseState->token.value.ptrRange.length)) != NULL)) {
- memcpy(parseState->cache.items[bucket].bytes, parseState->token.value.ptrRange.ptr, parseState->token.value.ptrRange.length);
- parseState->cache.items[bucket].object = (void *)CFRetain(parsedAtom);
- parseState->cache.items[bucket].hash = parseState->token.value.hash;
- parseState->cache.items[bucket].cfHash = 0UL;
- parseState->cache.items[bucket].size = parseState->token.value.ptrRange.length;
- parseState->cache.items[bucket].type = parseState->token.value.type;
- parseState->token.value.cacheItem = &parseState->cache.items[bucket];
- parseState->cache.age[bucket] = CDVJK_INIT_CACHE_AGE;
- } else { // The realloc failed, so clear the appropriate fields.
- parseState->cache.items[bucket].hash = 0UL;
- parseState->cache.items[bucket].cfHash = 0UL;
- parseState->cache.items[bucket].size = 0UL;
- parseState->cache.items[bucket].type = 0UL;
- }
- }
-
- return(parsedAtom);
-}
-
-
-static void *cdvjk_object_for_token(CDVJKParseState *parseState) {
- void *parsedAtom = NULL;
-
- parseState->token.value.cacheItem = NULL;
- switch(parseState->token.type) {
- case CDVJKTokenTypeString: parsedAtom = cdvjk_cachedObjects(parseState); break;
- case CDVJKTokenTypeNumber: parsedAtom = cdvjk_cachedObjects(parseState); break;
- case CDVJKTokenTypeObjectBegin: parsedAtom = cdvjk_parse_dictionary(parseState); break;
- case CDVJKTokenTypeArrayBegin: parsedAtom = cdvjk_parse_array(parseState); break;
- case CDVJKTokenTypeTrue: parsedAtom = (void *)kCFBooleanTrue; break;
- case CDVJKTokenTypeFalse: parsedAtom = (void *)kCFBooleanFalse; break;
- case CDVJKTokenTypeNull: parsedAtom = (void *)kCFNull; break;
- default: cdvjk_error(parseState, @"Internal error: Unknown token type. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); break;
- }
-
- return(parsedAtom);
-}
-
-#pragma mark -
-@implementation CDVJSONDecoder
-
-+ (id)decoder
-{
- return([self decoderWithParseOptions:CDVJKParseOptionStrict]);
-}
-
-+ (id)decoderWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags
-{
- return([[[self alloc] initWithParseOptions:parseOptionFlags] autorelease]);
-}
-
-- (id)init
-{
- return([self initWithParseOptions:CDVJKParseOptionStrict]);
-}
-
-- (id)initWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags
-{
- if((self = [super init]) == NULL) { return(NULL); }
-
- if(parseOptionFlags & ~CDVJKParseOptionValidFlags) { [self autorelease]; [NSException raise:NSInvalidArgumentException format:@"Invalid parse options."]; }
-
- if((parseState = (CDVJKParseState *)calloc(1UL, sizeof(CDVJKParseState))) == NULL) { goto errorExit; }
-
- parseState->parseOptionFlags = parseOptionFlags;
-
- parseState->token.tokenBuffer.roundSizeUpToMultipleOf = 4096UL;
- parseState->objectStack.roundSizeUpToMultipleOf = 2048UL;
-
- parseState->objCImpCache.NSNumberClass = _CDVjk_NSNumberClass;
- parseState->objCImpCache.NSNumberAlloc = _CDVjk_NSNumberAllocImp;
- parseState->objCImpCache.NSNumberInitWithUnsignedLongLong = _CDVjk_NSNumberInitWithUnsignedLongLongImp;
-
- parseState->cache.prng_lfsr = 1U;
- parseState->cache.count = CDVJK_CACHE_SLOTS;
- if((parseState->cache.items = (CDVJKTokenCacheItem *)calloc(1UL, sizeof(CDVJKTokenCacheItem) * parseState->cache.count)) == NULL) { goto errorExit; }
-
- return(self);
-
- errorExit:
- if(self) { [self autorelease]; self = NULL; }
- return(NULL);
-}
-
-// This is here primarily to support the NSString and NSData convenience functions so the autoreleased CDVJSONDecoder can release most of its resources before the pool pops.
-static void _JSONDecoderCleanup(CDVJSONDecoder *decoder) {
- if((decoder != NULL) && (decoder->parseState != NULL)) {
- cdvjk_managedBuffer_release(&decoder->parseState->token.tokenBuffer);
- cdvjk_objectStack_release(&decoder->parseState->objectStack);
-
- [decoder clearCache];
- if(decoder->parseState->cache.items != NULL) { free(decoder->parseState->cache.items); decoder->parseState->cache.items = NULL; }
-
- free(decoder->parseState); decoder->parseState = NULL;
- }
-}
-
-- (void)dealloc
-{
- _JSONDecoderCleanup(self);
- [super dealloc];
-}
-
-- (void)clearCache
-{
- if(CDVJK_EXPECT_T(parseState != NULL)) {
- if(CDVJK_EXPECT_T(parseState->cache.items != NULL)) {
- size_t idx = 0UL;
- for(idx = 0UL; idx < parseState->cache.count; idx++) {
- if(CDVJK_EXPECT_T(parseState->cache.items[idx].object != NULL)) { CFRelease(parseState->cache.items[idx].object); parseState->cache.items[idx].object = NULL; }
- if(CDVJK_EXPECT_T(parseState->cache.items[idx].bytes != NULL)) { free(parseState->cache.items[idx].bytes); parseState->cache.items[idx].bytes = NULL; }
- memset(&parseState->cache.items[idx], 0, sizeof(CDVJKTokenCacheItem));
- parseState->cache.age[idx] = 0U;
- }
- }
- }
-}
-
-// This needs to be completely rewritten.
-static id _CDVJKParseUTF8String(CDVJKParseState *parseState, BOOL mutableCollections, const unsigned char *string, size_t length, NSError **error) {
- NSCParameterAssert((parseState != NULL) && (string != NULL) && (parseState->cache.prng_lfsr != 0U));
- parseState->stringBuffer.bytes.ptr = string;
- parseState->stringBuffer.bytes.length = length;
- parseState->atIndex = 0UL;
- parseState->lineNumber = 1UL;
- parseState->lineStartIndex = 0UL;
- parseState->prev_atIndex = 0UL;
- parseState->prev_lineNumber = 1UL;
- parseState->prev_lineStartIndex = 0UL;
- parseState->error = NULL;
- parseState->errorIsPrev = 0;
- parseState->mutableCollections = (mutableCollections == NO) ? NO : YES;
-
- unsigned char stackTokenBuffer[CDVJK_TOKENBUFFER_SIZE] CDVJK_ALIGNED(64);
- cdvjk_managedBuffer_setToStackBuffer(&parseState->token.tokenBuffer, stackTokenBuffer, sizeof(stackTokenBuffer));
-
- void *stackObjects [CDVJK_STACK_OBJS] CDVJK_ALIGNED(64);
- void *stackKeys [CDVJK_STACK_OBJS] CDVJK_ALIGNED(64);
- CFHashCode stackCFHashes[CDVJK_STACK_OBJS] CDVJK_ALIGNED(64);
- cdvjk_objectStack_setToStackBuffer(&parseState->objectStack, stackObjects, stackKeys, stackCFHashes, CDVJK_STACK_OBJS);
-
- id parsedJSON = json_parse_it(parseState);
-
- if((error != NULL) && (parseState->error != NULL)) { *error = parseState->error; }
-
- cdvjk_managedBuffer_release(&parseState->token.tokenBuffer);
- cdvjk_objectStack_release(&parseState->objectStack);
-
- parseState->stringBuffer.bytes.ptr = NULL;
- parseState->stringBuffer.bytes.length = 0UL;
- parseState->atIndex = 0UL;
- parseState->lineNumber = 1UL;
- parseState->lineStartIndex = 0UL;
- parseState->prev_atIndex = 0UL;
- parseState->prev_lineNumber = 1UL;
- parseState->prev_lineStartIndex = 0UL;
- parseState->error = NULL;
- parseState->errorIsPrev = 0;
- parseState->mutableCollections = NO;
-
- return(parsedJSON);
-}
-
-////////////
-#pragma mark Deprecated as of v1.4
-////////////
-
-// Deprecated in CDVJSONKit v1.4. Use objectWithUTF8String:length: instead.
-- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length
-{
- return([self objectWithUTF8String:string length:length error:NULL]);
-}
-
-// Deprecated in CDVJSONKit v1.4. Use objectWithUTF8String:length:error: instead.
-- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length error:(NSError **)error
-{
- return([self objectWithUTF8String:string length:length error:error]);
-}
-
-// Deprecated in CDVJSONKit v1.4. Use objectWithData: instead.
-- (id)parseJSONData:(NSData *)jsonData
-{
- return([self objectWithData:jsonData error:NULL]);
-}
-
-// Deprecated in CDVJSONKit v1.4. Use objectWithData:error: instead.
-- (id)parseJSONData:(NSData *)jsonData error:(NSError **)error
-{
- return([self objectWithData:jsonData error:error]);
-}
-
-////////////
-#pragma mark Methods that return immutable collection objects
-////////////
-
-- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length
-{
- return([self objectWithUTF8String:string length:length error:NULL]);
-}
-
-- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error
-{
- if(parseState == NULL) { [NSException raise:NSInternalInconsistencyException format:@"parseState is NULL."]; }
- if(string == NULL) { [NSException raise:NSInvalidArgumentException format:@"The string argument is NULL."]; }
-
- return(_CDVJKParseUTF8String(parseState, NO, string, (size_t)length, error));
-}
-
-- (id)objectWithData:(NSData *)jsonData
-{
- return([self objectWithData:jsonData error:NULL]);
-}
-
-- (id)objectWithData:(NSData *)jsonData error:(NSError **)error
-{
- if(jsonData == NULL) { [NSException raise:NSInvalidArgumentException format:@"The jsonData argument is NULL."]; }
- return([self objectWithUTF8String:(const unsigned char *)[jsonData bytes] length:[jsonData length] error:error]);
-}
-
-////////////
-#pragma mark Methods that return mutable collection objects
-////////////
-
-- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length
-{
- return([self mutableObjectWithUTF8String:string length:length error:NULL]);
-}
-
-- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error
-{
- if(parseState == NULL) { [NSException raise:NSInternalInconsistencyException format:@"parseState is NULL."]; }
- if(string == NULL) { [NSException raise:NSInvalidArgumentException format:@"The string argument is NULL."]; }
-
- return(_CDVJKParseUTF8String(parseState, YES, string, (size_t)length, error));
-}
-
-- (id)mutableObjectWithData:(NSData *)jsonData
-{
- return([self mutableObjectWithData:jsonData error:NULL]);
-}
-
-- (id)mutableObjectWithData:(NSData *)jsonData error:(NSError **)error
-{
- if(jsonData == NULL) { [NSException raise:NSInvalidArgumentException format:@"The jsonData argument is NULL."]; }
- return([self mutableObjectWithUTF8String:(const unsigned char *)[jsonData bytes] length:[jsonData length] error:error]);
-}
-
-@end
-
-/*
- The NSString and NSData convenience methods need a little bit of explanation.
-
- Prior to CDVJSONKit v1.4, the NSString -objectFromJSONStringWithParseOptions:error: method looked like
-
- const unsigned char *utf8String = (const unsigned char *)[self UTF8String];
- if(utf8String == NULL) { return(NULL); }
- size_t utf8Length = strlen((const char *)utf8String);
- return([[JSONDecoder decoderWithParseOptions:parseOptionFlags] parseUTF8String:utf8String length:utf8Length error:error]);
-
- This changed with v1.4 to a more complicated method. The reason for this is to keep the amount of memory that is
- allocated, but not yet freed because it is dependent on the autorelease pool to pop before it can be reclaimed.
-
- In the simpler v1.3 code, this included all the bytes used to store the -UTF8String along with the CDVJSONDecoder and all its overhead.
-
- Now we use an autoreleased CFMutableData that is sized to the UTF8 length of the NSString in question and is used to hold the UTF8
- conversion of said string.
-
- Once parsed, the CFMutableData has its length set to 0. This should, hopefully, allow the CFMutableData to realloc and/or free
- the buffer.
-
- Another change made was a slight modification to CDVJSONDecoder so that most of the cleanup work that was done in -dealloc was moved
- to a private, internal function. These convenience routines keep the pointer to the autoreleased CDVJSONDecoder and calls
- _JSONDecoderCleanup() to early release the decoders resources since we already know that particular decoder is not going to be used
- again.
-
- If everything goes smoothly, this will most likely result in perhaps a few hundred bytes that are allocated but waiting for the
- autorelease pool to pop. This is compared to the thousands and easily hundreds of thousands of bytes that would have been in
- autorelease limbo. It's more complicated for us, but a win for the user.
-
- Autorelease objects are used in case things don't go smoothly. By having them autoreleased, we effectively guarantee that our
- requirement to -release the object is always met, not matter what goes wrong. The downside is having a an object or two in
- autorelease limbo, but we've done our best to minimize that impact, so it all balances out.
- */
-
-@implementation NSString (CDVJSONKitDeserializing)
-
-static id _NSStringObjectFromJSONString(NSString *jsonString, CDVJKParseOptionFlags parseOptionFlags, NSError **error, BOOL mutableCollection) {
- id returnObject = NULL;
- CFMutableDataRef mutableData = NULL;
- CDVJSONDecoder *decoder = NULL;
-
- CFIndex stringLength = CFStringGetLength((CFStringRef)jsonString);
- NSUInteger stringUTF8Length = [jsonString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
-
- if((mutableData = (CFMutableDataRef)[(id)CFDataCreateMutable(NULL, (NSUInteger)stringUTF8Length) autorelease]) != NULL) {
- UInt8 *utf8String = CFDataGetMutableBytePtr(mutableData);
- CFIndex usedBytes = 0L, convertedCount = 0L;
-
- convertedCount = CFStringGetBytes((CFStringRef)jsonString, CFRangeMake(0L, stringLength), kCFStringEncodingUTF8, '?', NO, utf8String, (NSUInteger)stringUTF8Length, &usedBytes);
- if(CDVJK_EXPECT_F(convertedCount != stringLength) || CDVJK_EXPECT_F(usedBytes < 0L)) { if(error != NULL) { *error = [NSError errorWithDomain:@"CDVJKErrorDomain" code:-1L userInfo:[NSDictionary dictionaryWithObject:@"An error occurred converting the contents of a NSString to UTF8." forKey:NSLocalizedDescriptionKey]]; } goto exitNow; }
-
- if(mutableCollection == NO) { returnObject = [(decoder = [CDVJSONDecoder decoderWithParseOptions:parseOptionFlags]) objectWithUTF8String:(const unsigned char *)utf8String length:(size_t)usedBytes error:error]; }
- else { returnObject = [(decoder = [CDVJSONDecoder decoderWithParseOptions:parseOptionFlags]) mutableObjectWithUTF8String:(const unsigned char *)utf8String length:(size_t)usedBytes error:error]; }
- }
-
-exitNow:
- if(mutableData != NULL) { CFDataSetLength(mutableData, 0L); }
- if(decoder != NULL) { _JSONDecoderCleanup(decoder); }
- return(returnObject);
-}
-
-- (id)cdvjk_objectFromJSONString
-{
- return([self cdvjk_objectFromJSONStringWithParseOptions:CDVJKParseOptionStrict error:NULL]);
-}
-
-- (id)cdvjk_objectFromJSONStringWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags
-{
- return([self cdvjk_objectFromJSONStringWithParseOptions:parseOptionFlags error:NULL]);
-}
-
-- (id)cdvjk_objectFromJSONStringWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags error:(NSError **)error
-{
- return(_NSStringObjectFromJSONString(self, parseOptionFlags, error, NO));
-}
-
-
-- (id)cdvjk_mutableObjectFromJSONString
-{
- return([self cdvjk_mutableObjectFromJSONStringWithParseOptions:CDVJKParseOptionStrict error:NULL]);
-}
-
-- (id)cdvjk_mutableObjectFromJSONStringWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags
-{
- return([self cdvjk_mutableObjectFromJSONStringWithParseOptions:parseOptionFlags error:NULL]);
-}
-
-- (id)cdvjk_mutableObjectFromJSONStringWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags error:(NSError **)error
-{
- return(_NSStringObjectFromJSONString(self, parseOptionFlags, error, YES));
-}
-
-@end
-
-@implementation NSData (CDVJSONKitDeserializing)
-
-- (id)cdvjk_objectFromJSONData
-{
- return([self cdvjk_objectFromJSONDataWithParseOptions:CDVJKParseOptionStrict error:NULL]);
-}
-
-- (id)cdvjk_objectFromJSONDataWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags
-{
- return([self cdvjk_objectFromJSONDataWithParseOptions:parseOptionFlags error:NULL]);
-}
-
-- (id)cdvjk_objectFromJSONDataWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags error:(NSError **)error
-{
- CDVJSONDecoder *decoder = NULL;
- id returnObject = [(decoder = [CDVJSONDecoder decoderWithParseOptions:parseOptionFlags]) objectWithData:self error:error];
- if(decoder != NULL) { _JSONDecoderCleanup(decoder); }
- return(returnObject);
-}
-
-- (id)cdvjk_mutableObjectFromJSONData
-{
- return([self cdvjk_mutableObjectFromJSONDataWithParseOptions:CDVJKParseOptionStrict error:NULL]);
-}
-
-- (id)cdvjk_mutableObjectFromJSONDataWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags
-{
- return([self cdvjk_mutableObjectFromJSONDataWithParseOptions:parseOptionFlags error:NULL]);
-}
-
-- (id)cdvjk_mutableObjectFromJSONDataWithParseOptions:(CDVJKParseOptionFlags)parseOptionFlags error:(NSError **)error
-{
- CDVJSONDecoder *decoder = NULL;
- id returnObject = [(decoder = [CDVJSONDecoder decoderWithParseOptions:parseOptionFlags]) mutableObjectWithData:self error:error];
- if(decoder != NULL) { _JSONDecoderCleanup(decoder); }
- return(returnObject);
-}
-
-
-@end
-
-////////////
-#pragma mark -
-#pragma mark Encoding / deserializing functions
-
-static void cdvjk_encode_error(CDVJKEncodeState *encodeState, NSString *format, ...) {
- NSCParameterAssert((encodeState != NULL) && (format != NULL));
-
- va_list varArgsList;
- va_start(varArgsList, format);
- NSString *formatString = [[[NSString alloc] initWithFormat:format arguments:varArgsList] autorelease];
- va_end(varArgsList);
-
- if(encodeState->error == NULL) {
- encodeState->error = [NSError errorWithDomain:@"CDVJKErrorDomain" code:-1L userInfo:
- [NSDictionary dictionaryWithObjectsAndKeys:
- formatString, NSLocalizedDescriptionKey,
- NULL]];
- }
-}
-
-CDVJK_STATIC_INLINE void cdvjk_encode_updateCache(CDVJKEncodeState *encodeState, CDVJKEncodeCache *cacheSlot, size_t startingAtIndex, id object) {
- NSCParameterAssert(encodeState != NULL);
- if(CDVJK_EXPECT_T(cacheSlot != NULL)) {
- NSCParameterAssert((object != NULL) && (startingAtIndex <= encodeState->atIndex));
- cacheSlot->object = object;
- cacheSlot->offset = startingAtIndex;
- cacheSlot->length = (size_t)(encodeState->atIndex - startingAtIndex);
- }
-}
-
-static int cdvjk_encode_printf(CDVJKEncodeState *encodeState, CDVJKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format, ...) {
- va_list varArgsList, varArgsListCopy;
- va_start(varArgsList, format);
- va_copy(varArgsListCopy, varArgsList);
-
- NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && (startingAtIndex <= encodeState->atIndex) && (format != NULL));
-
- ssize_t formattedStringLength = 0L;
- int returnValue = 0;
-
- if(CDVJK_EXPECT_T((formattedStringLength = vsnprintf((char *)&encodeState->stringBuffer.bytes.ptr[encodeState->atIndex], (encodeState->stringBuffer.bytes.length - encodeState->atIndex), format, varArgsList)) >= (ssize_t)(encodeState->stringBuffer.bytes.length - encodeState->atIndex))) {
- NSCParameterAssert(((encodeState->atIndex + (formattedStringLength * 2UL) + 256UL) > encodeState->stringBuffer.bytes.length));
- if(CDVJK_EXPECT_F(((encodeState->atIndex + (formattedStringLength * 2UL) + 256UL) > encodeState->stringBuffer.bytes.length)) && CDVJK_EXPECT_F((cdvjk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + (formattedStringLength * 2UL)+ 4096UL) == NULL))) { cdvjk_encode_error(encodeState, @"Unable to resize temporary buffer."); returnValue = 1; goto exitNow; }
- if(CDVJK_EXPECT_F((formattedStringLength = vsnprintf((char *)&encodeState->stringBuffer.bytes.ptr[encodeState->atIndex], (encodeState->stringBuffer.bytes.length - encodeState->atIndex), format, varArgsListCopy)) >= (ssize_t)(encodeState->stringBuffer.bytes.length - encodeState->atIndex))) { cdvjk_encode_error(encodeState, @"vsnprintf failed unexpectedly."); returnValue = 1; goto exitNow; }
- }
-
-exitNow:
- va_end(varArgsList);
- va_end(varArgsListCopy);
- if(CDVJK_EXPECT_T(returnValue == 0)) { encodeState->atIndex += formattedStringLength; cdvjk_encode_updateCache(encodeState, cacheSlot, startingAtIndex, object); }
- return(returnValue);
-}
-
-static int cdvjk_encode_write(CDVJKEncodeState *encodeState, CDVJKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format) {
- NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && (startingAtIndex <= encodeState->atIndex) && (format != NULL));
- if(CDVJK_EXPECT_F(((encodeState->atIndex + strlen(format) + 256UL) > encodeState->stringBuffer.bytes.length)) && CDVJK_EXPECT_F((cdvjk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + strlen(format) + 1024UL) == NULL))) { cdvjk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
-
- size_t formatIdx = 0UL;
- for(formatIdx = 0UL; format[formatIdx] != 0; formatIdx++) { NSCParameterAssert(encodeState->atIndex < encodeState->stringBuffer.bytes.length); encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = format[formatIdx]; }
- cdvjk_encode_updateCache(encodeState, cacheSlot, startingAtIndex, object);
- return(0);
-}
-
-static int cdvjk_encode_writePrettyPrintWhiteSpace(CDVJKEncodeState *encodeState) {
- NSCParameterAssert((encodeState != NULL) && ((encodeState->serializeOptionFlags & CDVJKSerializeOptionPretty) != 0UL));
- if(CDVJK_EXPECT_F((encodeState->atIndex + ((encodeState->depth + 1UL) * 2UL) + 16UL) > encodeState->stringBuffer.bytes.length) && CDVJK_EXPECT_T(cdvjk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + ((encodeState->depth + 1UL) * 2UL) + 4096UL) == NULL)) { cdvjk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
- encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\n';
- size_t depthWhiteSpace = 0UL;
- for(depthWhiteSpace = 0UL; depthWhiteSpace < (encodeState->depth * 2UL); depthWhiteSpace++) { NSCParameterAssert(encodeState->atIndex < encodeState->stringBuffer.bytes.length); encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = ' '; }
- return(0);
-}
-
-static int cdvjk_encode_write1slow(CDVJKEncodeState *encodeState, ssize_t depthChange, const char *format) {
- NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && (format != NULL) && ((depthChange >= -1L) && (depthChange <= 1L)) && ((encodeState->depth == 0UL) ? (depthChange >= 0L) : 1) && ((encodeState->serializeOptionFlags & CDVJKSerializeOptionPretty) != 0UL));
- if(CDVJK_EXPECT_F((encodeState->atIndex + ((encodeState->depth + 1UL) * 2UL) + 16UL) > encodeState->stringBuffer.bytes.length) && CDVJK_EXPECT_F(cdvjk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + ((encodeState->depth + 1UL) * 2UL) + 4096UL) == NULL)) { cdvjk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
- encodeState->depth += depthChange;
- if(CDVJK_EXPECT_T(format[0] == ':')) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = format[0]; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = ' '; }
- else {
- if(CDVJK_EXPECT_F(depthChange == -1L)) { if(CDVJK_EXPECT_F(cdvjk_encode_writePrettyPrintWhiteSpace(encodeState))) { return(1); } }
- encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = format[0];
- if(CDVJK_EXPECT_T(depthChange != -1L)) { if(CDVJK_EXPECT_F(cdvjk_encode_writePrettyPrintWhiteSpace(encodeState))) { return(1); } }
- }
- NSCParameterAssert(encodeState->atIndex < encodeState->stringBuffer.bytes.length);
- return(0);
-}
-
-static int cdvjk_encode_write1fast(CDVJKEncodeState *encodeState, ssize_t depthChange CDVJK_UNUSED_ARG, const char *format) {
- NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && ((encodeState->serializeOptionFlags & CDVJKSerializeOptionPretty) == 0UL));
- if(CDVJK_EXPECT_T((encodeState->atIndex + 4UL) < encodeState->stringBuffer.bytes.length)) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = format[0]; }
- else { return(cdvjk_encode_write(encodeState, NULL, 0UL, NULL, format)); }
- return(0);
-}
-
-static int cdvjk_encode_writen(CDVJKEncodeState *encodeState, CDVJKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format, size_t length) {
- NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && (startingAtIndex <= encodeState->atIndex));
- if(CDVJK_EXPECT_F((encodeState->stringBuffer.bytes.length - encodeState->atIndex) < (length + 4UL))) { if(cdvjk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + 4096UL + length) == NULL) { cdvjk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); } }
- memcpy(encodeState->stringBuffer.bytes.ptr + encodeState->atIndex, format, length);
- encodeState->atIndex += length;
- cdvjk_encode_updateCache(encodeState, cacheSlot, startingAtIndex, object);
- return(0);
-}
-
-CDVJK_STATIC_INLINE CDVJKHash cdvjk_encode_object_hash(void *objectPtr) {
- return( ( (((CDVJKHash)objectPtr) >> 21) ^ (((CDVJKHash)objectPtr) >> 9) ) + (((CDVJKHash)objectPtr) >> 4) );
-}
-
-static int cdvjk_encode_add_atom_to_buffer(CDVJKEncodeState *encodeState, void *objectPtr) {
- NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && (objectPtr != NULL));
-
- id object = (id)objectPtr, encodeCacheObject = object;
- int isClass = CDVJKClassUnknown;
- size_t startingAtIndex = encodeState->atIndex;
-
- CDVJKHash objectHash = cdvjk_encode_object_hash(objectPtr);
- CDVJKEncodeCache *cacheSlot = &encodeState->cache[objectHash % CDVJK_ENCODE_CACHE_SLOTS];
-
- if(CDVJK_EXPECT_T(cacheSlot->object == object)) {
- NSCParameterAssert((cacheSlot->object != NULL) &&
- (cacheSlot->offset < encodeState->atIndex) && ((cacheSlot->offset + cacheSlot->length) < encodeState->atIndex) &&
- (cacheSlot->offset < encodeState->stringBuffer.bytes.length) && ((cacheSlot->offset + cacheSlot->length) < encodeState->stringBuffer.bytes.length) &&
- ((encodeState->stringBuffer.bytes.ptr + encodeState->atIndex) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
- ((encodeState->stringBuffer.bytes.ptr + cacheSlot->offset) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
- ((encodeState->stringBuffer.bytes.ptr + cacheSlot->offset + cacheSlot->length) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)));
- if(CDVJK_EXPECT_F(((encodeState->atIndex + cacheSlot->length + 256UL) > encodeState->stringBuffer.bytes.length)) && CDVJK_EXPECT_F((cdvjk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + cacheSlot->length + 1024UL) == NULL))) { cdvjk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
- NSCParameterAssert(((encodeState->atIndex + cacheSlot->length) < encodeState->stringBuffer.bytes.length) &&
- ((encodeState->stringBuffer.bytes.ptr + encodeState->atIndex) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
- ((encodeState->stringBuffer.bytes.ptr + encodeState->atIndex + cacheSlot->length) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
- ((encodeState->stringBuffer.bytes.ptr + cacheSlot->offset) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
- ((encodeState->stringBuffer.bytes.ptr + cacheSlot->offset + cacheSlot->length) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
- ((encodeState->stringBuffer.bytes.ptr + cacheSlot->offset + cacheSlot->length) < (encodeState->stringBuffer.bytes.ptr + encodeState->atIndex)));
- memcpy(encodeState->stringBuffer.bytes.ptr + encodeState->atIndex, encodeState->stringBuffer.bytes.ptr + cacheSlot->offset, cacheSlot->length);
- encodeState->atIndex += cacheSlot->length;
- return(0);
- }
-
- // When we encounter a class that we do not handle, and we have either a delegate or block that the user supplied to format unsupported classes,
- // we "re-run" the object check. However, we re-run the object check exactly ONCE. If the user supplies an object that isn't one of the
- // supported classes, we fail the second time (i.e., double fault error).
- BOOL rerunningAfterClassFormatter = NO;
- rerunAfterClassFormatter:;
-
- // XXX XXX XXX XXX
- //
- // We need to work around a bug in 10.7, which breaks ABI compatibility with Objective-C going back not just to 10.0, but OpenStep and even NextStep.
- //
- // It has long been documented that "the very first thing that a pointer to an Objective-C object "points to" is a pointer to that objects class".
- //
- // This is euphemistically called "tagged pointers". There are a number of highly technical problems with this, most involving long passages from
- // the C standard(s). In short, one can make a strong case, couched from the perspective of the C standard(s), that that 10.7 "tagged pointers" are
- // fundamentally Wrong and Broken, and should have never been implemented. Assuming those points are glossed over, because the change is very clearly
- // breaking ABI compatibility, this should have resulted in a minimum of a "minimum version required" bump in various shared libraries to prevent
- // causes code that used to work just fine to suddenly break without warning.
- //
- // In fact, the C standard says that the hack below is "undefined behavior"- there is no requirement that the 10.7 tagged pointer hack of setting the
- // "lower, unused bits" must be preserved when casting the result to an integer type, but this "works" because for most architectures
- // `sizeof(long) == sizeof(void *)` and the compiler uses the same representation for both. (note: this is informal, not meant to be
- // normative or pedantically correct).
- //
- // In other words, while this "works" for now, technically the compiler is not obligated to do "what we want", and a later version of the compiler
- // is not required in any way to produce the same results or behavior that earlier versions of the compiler did for the statement below.
- //
- // Fan-fucking-tastic.
- //
- // Why not just use `object_getClass()`? Because `object->isa` reduces to (typically) a *single* instruction. Calling `object_getClass()` requires
- // that the compiler potentially spill registers, establish a function call frame / environment, and finally execute a "jump subroutine" instruction.
- // Then, the called subroutine must spend half a dozen instructions in its prolog, however many instructions doing whatever it does, then half a dozen
- // instructions in its prolog. One instruction compared to dozens, maybe a hundred instructions.
- //
- // Yes, that's one to two orders of magnitude difference. Which is compelling in its own right. When going for performance, you're often happy with
- // gains in the two to three percent range.
- //
- // XXX XXX XXX XXX
-
- BOOL workAroundMacOSXABIBreakingBug = NO;
- if(CDVJK_EXPECT_F(((NSUInteger)object) & 0x1)) { workAroundMacOSXABIBreakingBug = YES; goto slowClassLookup; }
-
- if(CDVJK_EXPECT_T(object_getClass(object) == encodeState->fastClassLookup.stringClass)) { isClass = CDVJKClassString; }
- else if(CDVJK_EXPECT_T(object_getClass(object) == encodeState->fastClassLookup.numberClass)) { isClass = CDVJKClassNumber; }
- else if(CDVJK_EXPECT_T(object_getClass(object) == encodeState->fastClassLookup.dictionaryClass)) { isClass = CDVJKClassDictionary; }
- else if(CDVJK_EXPECT_T(object_getClass(object) == encodeState->fastClassLookup.arrayClass)) { isClass = CDVJKClassArray; }
- else if(CDVJK_EXPECT_T(object_getClass(object) == encodeState->fastClassLookup.nullClass)) { isClass = CDVJKClassNull; }
- else {
- slowClassLookup:
- if(CDVJK_EXPECT_T([object isKindOfClass:[NSString class]])) { if(workAroundMacOSXABIBreakingBug == NO) { encodeState->fastClassLookup.stringClass = object_getClass(object); } isClass = CDVJKClassString; }
- else if(CDVJK_EXPECT_T([object isKindOfClass:[NSNumber class]])) { if(workAroundMacOSXABIBreakingBug == NO) { encodeState->fastClassLookup.numberClass = object_getClass(object); } isClass = CDVJKClassNumber; }
- else if(CDVJK_EXPECT_T([object isKindOfClass:[NSDictionary class]])) { if(workAroundMacOSXABIBreakingBug == NO) { encodeState->fastClassLookup.dictionaryClass = object_getClass(object); } isClass = CDVJKClassDictionary; }
- else if(CDVJK_EXPECT_T([object isKindOfClass:[NSArray class]])) { if(workAroundMacOSXABIBreakingBug == NO) { encodeState->fastClassLookup.arrayClass = object_getClass(object); } isClass = CDVJKClassArray; }
- else if(CDVJK_EXPECT_T([object isKindOfClass:[NSNull class]])) { if(workAroundMacOSXABIBreakingBug == NO) { encodeState->fastClassLookup.nullClass = object_getClass(object); } isClass = CDVJKClassNull; }
- else {
- if((rerunningAfterClassFormatter == NO) && (
-#ifdef __BLOCKS__
- ((encodeState->classFormatterBlock) && ((object = encodeState->classFormatterBlock(object)) != NULL)) ||
-#endif
- ((encodeState->classFormatterIMP) && ((object = encodeState->classFormatterIMP(encodeState->classFormatterDelegate, encodeState->classFormatterSelector, object)) != NULL)) )) { rerunningAfterClassFormatter = YES; goto rerunAfterClassFormatter; }
-
- if(rerunningAfterClassFormatter == NO) { cdvjk_encode_error(encodeState, @"Unable to serialize object class %@.", NSStringFromClass([encodeCacheObject class])); return(1); }
- else { cdvjk_encode_error(encodeState, @"Unable to serialize object class %@ that was returned by the unsupported class formatter. Original object class was %@.", (object == NULL) ? @"NULL" : NSStringFromClass([object class]), NSStringFromClass([encodeCacheObject class])); return(1); }
- }
- }
-
- // This is here for the benefit of the optimizer. It allows the optimizer to do loop invariant code motion for the CDVJKClassArray
- // and CDVJKClassDictionary cases when printing simple, single characters via cdvjk_encode_write(), which is actually a macro:
- // #define cdvjk_encode_write1(es, dc, f) (_jk_encode_prettyPrint ? cdvjk_encode_write1slow(es, dc, f) : cdvjk_encode_write1fast(es, dc, f))
- int _jk_encode_prettyPrint = CDVJK_EXPECT_T((encodeState->serializeOptionFlags & CDVJKSerializeOptionPretty) == 0) ? 0 : 1;
-
- switch(isClass) {
- case CDVJKClassString:
- {
- {
- const unsigned char *cStringPtr = (const unsigned char *)CFStringGetCStringPtr((CFStringRef)object, kCFStringEncodingMacRoman);
- if(cStringPtr != NULL) {
- const unsigned char *utf8String = cStringPtr;
- size_t utf8Idx = 0UL;
-
- CFIndex stringLength = CFStringGetLength((CFStringRef)object);
- if(CDVJK_EXPECT_F(((encodeState->atIndex + (stringLength * 2UL) + 256UL) > encodeState->stringBuffer.bytes.length)) && CDVJK_EXPECT_F((cdvjk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + (stringLength * 2UL) + 1024UL) == NULL))) { cdvjk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
-
- if(CDVJK_EXPECT_T((encodeState->encodeOption & CDVJKEncodeOptionStringObjTrimQuotes) == 0UL)) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\"'; }
- for(utf8Idx = 0UL; utf8String[utf8Idx] != 0U; utf8Idx++) {
- NSCParameterAssert(((&encodeState->stringBuffer.bytes.ptr[encodeState->atIndex]) - encodeState->stringBuffer.bytes.ptr) < (ssize_t)encodeState->stringBuffer.bytes.length);
- NSCParameterAssert(encodeState->atIndex < encodeState->stringBuffer.bytes.length);
- if(CDVJK_EXPECT_F(utf8String[utf8Idx] >= 0x80U)) { encodeState->atIndex = startingAtIndex; goto slowUTF8Path; }
- if(CDVJK_EXPECT_F(utf8String[utf8Idx] < 0x20U)) {
- switch(utf8String[utf8Idx]) {
- case '\b': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'b'; break;
- case '\f': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'f'; break;
- case '\n': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'n'; break;
- case '\r': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'r'; break;
- case '\t': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 't'; break;
- default: if(CDVJK_EXPECT_F(cdvjk_encode_printf(encodeState, NULL, 0UL, NULL, "\\u%4.4x", utf8String[utf8Idx]))) { return(1); } break;
- }
- } else {
- if(CDVJK_EXPECT_F(utf8String[utf8Idx] == '\"') || CDVJK_EXPECT_F(utf8String[utf8Idx] == '\\') || (CDVJK_EXPECT_F(encodeState->serializeOptionFlags & CDVJKSerializeOptionEscapeForwardSlashes) && CDVJK_EXPECT_F(utf8String[utf8Idx] == '/'))) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; }
- encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = utf8String[utf8Idx];
- }
- }
- NSCParameterAssert((encodeState->atIndex + 1UL) < encodeState->stringBuffer.bytes.length);
- if(CDVJK_EXPECT_T((encodeState->encodeOption & CDVJKEncodeOptionStringObjTrimQuotes) == 0UL)) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\"'; }
- cdvjk_encode_updateCache(encodeState, cacheSlot, startingAtIndex, encodeCacheObject);
- return(0);
- }
- }
-
- slowUTF8Path:
- {
- CFIndex stringLength = CFStringGetLength((CFStringRef)object);
- CFIndex maxStringUTF8Length = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 32L;
-
- if(CDVJK_EXPECT_F((size_t)maxStringUTF8Length > encodeState->utf8ConversionBuffer.bytes.length) && CDVJK_EXPECT_F(cdvjk_managedBuffer_resize(&encodeState->utf8ConversionBuffer, maxStringUTF8Length + 1024UL) == NULL)) { cdvjk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
-
- CFIndex usedBytes = 0L, convertedCount = 0L;
- convertedCount = CFStringGetBytes((CFStringRef)object, CFRangeMake(0L, stringLength), kCFStringEncodingUTF8, '?', NO, encodeState->utf8ConversionBuffer.bytes.ptr, encodeState->utf8ConversionBuffer.bytes.length - 16L, &usedBytes);
- if(CDVJK_EXPECT_F(convertedCount != stringLength) || CDVJK_EXPECT_F(usedBytes < 0L)) { cdvjk_encode_error(encodeState, @"An error occurred converting the contents of a NSString to UTF8."); return(1); }
-
- if(CDVJK_EXPECT_F((encodeState->atIndex + (maxStringUTF8Length * 2UL) + 256UL) > encodeState->stringBuffer.bytes.length) && CDVJK_EXPECT_F(cdvjk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + (maxStringUTF8Length * 2UL) + 1024UL) == NULL)) { cdvjk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
-
- const unsigned char *utf8String = encodeState->utf8ConversionBuffer.bytes.ptr;
-
- size_t utf8Idx = 0UL;
- if(CDVJK_EXPECT_T((encodeState->encodeOption & CDVJKEncodeOptionStringObjTrimQuotes) == 0UL)) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\"'; }
- for(utf8Idx = 0UL; utf8Idx < (size_t)usedBytes; utf8Idx++) {
- NSCParameterAssert(((&encodeState->stringBuffer.bytes.ptr[encodeState->atIndex]) - encodeState->stringBuffer.bytes.ptr) < (ssize_t)encodeState->stringBuffer.bytes.length);
- NSCParameterAssert(encodeState->atIndex < encodeState->stringBuffer.bytes.length);
- NSCParameterAssert((CFIndex)utf8Idx < usedBytes);
- if(CDVJK_EXPECT_F(utf8String[utf8Idx] < 0x20U)) {
- switch(utf8String[utf8Idx]) {
- case '\b': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'b'; break;
- case '\f': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'f'; break;
- case '\n': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'n'; break;
- case '\r': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'r'; break;
- case '\t': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 't'; break;
- default: if(CDVJK_EXPECT_F(cdvjk_encode_printf(encodeState, NULL, 0UL, NULL, "\\u%4.4x", utf8String[utf8Idx]))) { return(1); } break;
- }
- } else {
- if(CDVJK_EXPECT_F(utf8String[utf8Idx] >= 0x80U) && (encodeState->serializeOptionFlags & CDVJKSerializeOptionEscapeUnicode)) {
- const unsigned char *nextValidCharacter = NULL;
- UTF32 u32ch = 0U;
- CDV_ConversionResult result;
-
- if(CDVJK_EXPECT_F((result = cdvConvertSingleCodePointInUTF8(&utf8String[utf8Idx], &utf8String[usedBytes], (UTF8 const **)&nextValidCharacter, &u32ch)) != conversionOK)) { cdvjk_encode_error(encodeState, @"Error converting UTF8."); return(1); }
- else {
- utf8Idx = (nextValidCharacter - utf8String) - 1UL;
- if(CDVJK_EXPECT_T(u32ch <= 0xffffU)) { if(CDVJK_EXPECT_F(cdvjk_encode_printf(encodeState, NULL, 0UL, NULL, "\\u%4.4x", u32ch))) { return(1); } }
- else { if(CDVJK_EXPECT_F(cdvjk_encode_printf(encodeState, NULL, 0UL, NULL, "\\u%4.4x\\u%4.4x", (0xd7c0U + (u32ch >> 10)), (0xdc00U + (u32ch & 0x3ffU))))) { return(1); } }
- }
- } else {
- if(CDVJK_EXPECT_F(utf8String[utf8Idx] == '\"') || CDVJK_EXPECT_F(utf8String[utf8Idx] == '\\') || (CDVJK_EXPECT_F(encodeState->serializeOptionFlags & CDVJKSerializeOptionEscapeForwardSlashes) && CDVJK_EXPECT_F(utf8String[utf8Idx] == '/'))) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; }
- encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = utf8String[utf8Idx];
- }
- }
- }
- NSCParameterAssert((encodeState->atIndex + 1UL) < encodeState->stringBuffer.bytes.length);
- if(CDVJK_EXPECT_T((encodeState->encodeOption & CDVJKEncodeOptionStringObjTrimQuotes) == 0UL)) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\"'; }
- cdvjk_encode_updateCache(encodeState, cacheSlot, startingAtIndex, encodeCacheObject);
- return(0);
- }
- }
- break;
-
- case CDVJKClassNumber:
- {
- if(object == (id)kCFBooleanTrue) { return(cdvjk_encode_writen(encodeState, cacheSlot, startingAtIndex, encodeCacheObject, "true", 4UL)); }
- else if(object == (id)kCFBooleanFalse) { return(cdvjk_encode_writen(encodeState, cacheSlot, startingAtIndex, encodeCacheObject, "false", 5UL)); }
-
- const char *objCType = [object objCType];
- char anum[256], *aptr = &anum[255];
- int isNegative = 0;
- unsigned long long ullv;
- long long llv;
-
- if(CDVJK_EXPECT_F(objCType == NULL) || CDVJK_EXPECT_F(objCType[0] == 0) || CDVJK_EXPECT_F(objCType[1] != 0)) { cdvjk_encode_error(encodeState, @"NSNumber conversion error, unknown type. Type: '%s'", (objCType == NULL) ? "<NULL>" : objCType); return(1); }
-
- switch(objCType[0]) {
- case 'c': case 'i': case 's': case 'l': case 'q':
- if(CDVJK_EXPECT_T(CFNumberGetValue((CFNumberRef)object, kCFNumberLongLongType, &llv))) {
- if(llv < 0LL) { ullv = -llv; isNegative = 1; } else { ullv = llv; isNegative = 0; }
- goto convertNumber;
- } else { cdvjk_encode_error(encodeState, @"Unable to get scalar value from number object."); return(1); }
- break;
- case 'C': case 'I': case 'S': case 'L': case 'Q': case 'B':
- if(CDVJK_EXPECT_T(CFNumberGetValue((CFNumberRef)object, kCFNumberLongLongType, &ullv))) {
- convertNumber:
- if(CDVJK_EXPECT_F(ullv < 10ULL)) { *--aptr = ullv + '0'; } else { while(CDVJK_EXPECT_T(ullv > 0ULL)) { *--aptr = (ullv % 10ULL) + '0'; ullv /= 10ULL; NSCParameterAssert(aptr > anum); } }
- if(isNegative) { *--aptr = '-'; }
- NSCParameterAssert(aptr > anum);
- return(cdvjk_encode_writen(encodeState, cacheSlot, startingAtIndex, encodeCacheObject, aptr, &anum[255] - aptr));
- } else { cdvjk_encode_error(encodeState, @"Unable to get scalar value from number object."); return(1); }
- break;
- case 'f': case 'd':
- {
- double dv;
- if(CDVJK_EXPECT_T(CFNumberGetValue((CFNumberRef)object, kCFNumberDoubleType, &dv))) {
- if(CDVJK_EXPECT_F(!isfinite(dv))) { cdvjk_encode_error(encodeState, @"Floating point values must be finite. CDVJSON does not support NaN or Infinity."); return(1); }
- return(cdvjk_encode_printf(encodeState, cacheSlot, startingAtIndex, encodeCacheObject, "%.17g", dv));
- } else { cdvjk_encode_error(encodeState, @"Unable to get floating point value from number object."); return(1); }
- }
- break;
- default: cdvjk_encode_error(encodeState, @"NSNumber conversion error, unknown type. Type: '%c' / 0x%2.2x", objCType[0], objCType[0]); return(1); break;
- }
- }
- break;
-
- case CDVJKClassArray:
- {
- int printComma = 0;
- CFIndex arrayCount = CFArrayGetCount((CFArrayRef)object), idx = 0L;
- if(CDVJK_EXPECT_F(cdvjk_encode_write1(encodeState, 1L, "["))) { return(1); }
- if(CDVJK_EXPECT_F(arrayCount > 1020L)) {
- for(id arrayObject in object) { if(CDVJK_EXPECT_T(printComma)) { if(CDVJK_EXPECT_F(cdvjk_encode_write1(encodeState, 0L, ","))) { return(1); } } printComma = 1; if(CDVJK_EXPECT_F(cdvjk_encode_add_atom_to_buffer(encodeState, arrayObject))) { return(1); } }
- } else {
- void *objects[1024];
- CFArrayGetValues((CFArrayRef)object, CFRangeMake(0L, arrayCount), (const void **)objects);
- for(idx = 0L; idx < arrayCount; idx++) { if(CDVJK_EXPECT_T(printComma)) { if(CDVJK_EXPECT_F(cdvjk_encode_write1(encodeState, 0L, ","))) { return(1); } } printComma = 1; if(CDVJK_EXPECT_F(cdvjk_encode_add_atom_to_buffer(encodeState, objects[idx]))) { return(1); } }
- }
- return(cdvjk_encode_write1(encodeState, -1L, "]"));
- }
- break;
-
- case CDVJKClassDictionary:
- {
- int printComma = 0;
- CFIndex dictionaryCount = CFDictionaryGetCount((CFDictionaryRef)object), idx = 0L;
- id enumerateObject = CDVJK_EXPECT_F(_jk_encode_prettyPrint) ? [[object allKeys] sortedArrayUsingSelector:@selector(compare:)] : object;
-
- if(CDVJK_EXPECT_F(cdvjk_encode_write1(encodeState, 1L, "{"))) { return(1); }
- if(CDVJK_EXPECT_F(_jk_encode_prettyPrint) || CDVJK_EXPECT_F(dictionaryCount > 1020L)) {
- for(id keyObject in enumerateObject) {
- if(CDVJK_EXPECT_T(printComma)) { if(CDVJK_EXPECT_F(cdvjk_encode_write1(encodeState, 0L, ","))) { return(1); } }
- printComma = 1;
- if(CDVJK_EXPECT_F((object_getClass(keyObject) != encodeState->fastClassLookup.stringClass)) && CDVJK_EXPECT_F(([keyObject isKindOfClass:[NSString class]] == NO))) { cdvjk_encode_error(encodeState, @"Key must be a string object."); return(1); }
- if(CDVJK_EXPECT_F(cdvjk_encode_add_atom_to_buffer(encodeState, keyObject))) { return(1); }
- if(CDVJK_EXPECT_F(cdvjk_encode_write1(encodeState, 0L, ":"))) { return(1); }
- if(CDVJK_EXPECT_F(cdvjk_encode_add_atom_to_buffer(encodeState, (void *)CFDictionaryGetValue((CFDictionaryRef)object, keyObject)))) { return(1); }
- }
- } else {
- void *keys[1024], *objects[1024];
- CFDictionaryGetKeysAndValues((CFDictionaryRef)object, (const void **)keys, (const void **)objects);
- for(idx = 0L; idx < dictionaryCount; idx++) {
- if(CDVJK_EXPECT_T(printComma)) { if(CDVJK_EXPECT_F(cdvjk_encode_write1(encodeState, 0L, ","))) { return(1); } }
- printComma = 1;
- if(CDVJK_EXPECT_F(object_getClass(((id)keys[idx])) != encodeState->fastClassLookup.stringClass) && CDVJK_EXPECT_F([(id)keys[idx] isKindOfClass:[NSString class]] == NO)) { cdvjk_encode_error(encodeState, @"Key must be a string object."); return(1); }
- if(CDVJK_EXPECT_F(cdvjk_encode_add_atom_to_buffer(encodeState, keys[idx]))) { return(1); }
- if(CDVJK_EXPECT_F(cdvjk_encode_write1(encodeState, 0L, ":"))) { return(1); }
- if(CDVJK_EXPECT_F(cdvjk_encode_add_atom_to_buffer(encodeState, objects[idx]))) { return(1); }
- }
- }
- return(cdvjk_encode_write1(encodeState, -1L, "}"));
- }
- break;
-
- case CDVJKClassNull: return(cdvjk_encode_writen(encodeState, cacheSlot, startingAtIndex, encodeCacheObject, "null", 4UL)); break;
-
- default: cdvjk_encode_error(encodeState, @"Unable to serialize object class %@.", NSStringFromClass([object class])); return(1); break;
- }
-
- return(0);
-}
-
-
-@implementation CDVJKSerializer
-
-+ (id)serializeObject:(id)object options:(CDVJKSerializeOptionFlags)optionFlags encodeOption:(CDVJKEncodeOptionType)encodeOption block:(CDVJKSERIALIZER_BLOCKS_PROTO)block delegate:(id)delegate selector:(SEL)selector error:(NSError **)error
-{
- return([[[[self alloc] init] autorelease] serializeObject:object options:optionFlags encodeOption:encodeOption block:block delegate:delegate selector:selector error:error]);
-}
-
-- (id)serializeObject:(id)object options:(CDVJKSerializeOptionFlags)optionFlags encodeOption:(CDVJKEncodeOptionType)encodeOption block:(CDVJKSERIALIZER_BLOCKS_PROTO)block delegate:(id)delegate selector:(SEL)selector error:(NSError **)error
-{
-#ifndef __BLOCKS__
-#pragma unused(block)
-#endif
- NSParameterAssert((object != NULL) && (encodeState == NULL) && ((delegate != NULL) ? (block == NULL) : 1) && ((block != NULL) ? (delegate == NULL) : 1) &&
- (((encodeOption & CDVJKEncodeOptionCollectionObj) != 0UL) ? (((encodeOption & CDVJKEncodeOptionStringObj) == 0UL) && ((encodeOption & CDVJKEncodeOptionStringObjTrimQuotes) == 0UL)) : 1) &&
- (((encodeOption & CDVJKEncodeOptionStringObj) != 0UL) ? ((encodeOption & CDVJKEncodeOptionCollectionObj) == 0UL) : 1));
-
- id returnObject = NULL;
-
- if(encodeState != NULL) { [self releaseState]; }
- if((encodeState = (struct CDVJKEncodeState *)calloc(1UL, sizeof(CDVJKEncodeState))) == NULL) { [NSException raise:NSMallocException format:@"Unable to allocate state structure."]; return(NULL); }
-
- if((error != NULL) && (*error != NULL)) { *error = NULL; }
-
- if(delegate != NULL) {
- if(selector == NULL) { [NSException raise:NSInvalidArgumentException format:@"The delegate argument is not NULL, but the selector argument is NULL."]; }
- if([delegate respondsToSelector:selector] == NO) { [NSException raise:NSInvalidArgumentException format:@"The serializeUnsupportedClassesUsingDelegate: delegate does not respond to the selector argument."]; }
- encodeState->classFormatterDelegate = delegate;
- encodeState->classFormatterSelector = selector;
- encodeState->classFormatterIMP = (CDVJKClassFormatterIMP)[delegate methodForSelector:selector];
- NSCParameterAssert(encodeState->classFormatterIMP != NULL);
- }
-
-#ifdef __BLOCKS__
- encodeState->classFormatterBlock = block;
-#endif
- encodeState->serializeOptionFlags = optionFlags;
- encodeState->encodeOption = encodeOption;
- encodeState->stringBuffer.roundSizeUpToMultipleOf = (1024UL * 32UL);
- encodeState->utf8ConversionBuffer.roundSizeUpToMultipleOf = 4096UL;
-
- unsigned char stackJSONBuffer[CDVJK_JSONBUFFER_SIZE] CDVJK_ALIGNED(64);
- cdvjk_managedBuffer_setToStackBuffer(&encodeState->stringBuffer, stackJSONBuffer, sizeof(stackJSONBuffer));
-
- unsigned char stackUTF8Buffer[CDVJK_UTF8BUFFER_SIZE] CDVJK_ALIGNED(64);
- cdvjk_managedBuffer_setToStackBuffer(&encodeState->utf8ConversionBuffer, stackUTF8Buffer, sizeof(stackUTF8Buffer));
-
- if(((encodeOption & CDVJKEncodeOptionCollectionObj) != 0UL) && (([object isKindOfClass:[NSArray class]] == NO) && ([object isKindOfClass:[NSDictionary class]] == NO))) { cdvjk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSArray or NSDictionary.", NSStringFromClass([object class])); goto errorExit; }
- if(((encodeOption & CDVJKEncodeOptionStringObj) != 0UL) && ([object isKindOfClass:[NSString class]] == NO)) { cdvjk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSString.", NSStringFromClass([object class])); goto errorExit; }
-
- if(cdvjk_encode_add_atom_to_buffer(encodeState, object) == 0) {
- BOOL stackBuffer = ((encodeState->stringBuffer.flags & CDVJKManagedBufferMustFree) == 0UL) ? YES : NO;
-
- if((encodeState->atIndex < 2UL))
- if((stackBuffer == NO) && ((encodeState->stringBuffer.bytes.ptr = (unsigned char *)reallocf(encodeState->stringBuffer.bytes.ptr, encodeState->atIndex + 16UL)) == NULL)) { cdvjk_encode_error(encodeState, @"Unable to realloc buffer"); goto errorExit; }
-
- switch((encodeOption & CDVJKEncodeOptionAsTypeMask)) {
- case CDVJKEncodeOptionAsData:
- if(stackBuffer == YES) { if((returnObject = [(id)CFDataCreate( NULL, encodeState->stringBuffer.bytes.ptr, (CFIndex)encodeState->atIndex) autorelease]) == NULL) { cdvjk_encode_error(encodeState, @"Unable to create NSData object"); } }
- else { if((returnObject = [(id)CFDataCreateWithBytesNoCopy( NULL, encodeState->stringBuffer.bytes.ptr, (CFIndex)encodeState->atIndex, NULL) autorelease]) == NULL) { cdvjk_encode_error(encodeState, @"Unable to create NSData object"); } }
- break;
-
- case CDVJKEncodeOptionAsString:
- if(stackBuffer == YES) { if((returnObject = [(id)CFStringCreateWithBytes( NULL, (const UInt8 *)encodeState->stringBuffer.bytes.ptr, (CFIndex)encodeState->atIndex, kCFStringEncodingUTF8, NO) autorelease]) == NULL) { cdvjk_encode_error(encodeState, @"Unable to create NSString object"); } }
- else { if((returnObject = [(id)CFStringCreateWithBytesNoCopy(NULL, (const UInt8 *)encodeState->stringBuffer.bytes.ptr, (CFIndex)encodeState->atIndex, kCFStringEncodingUTF8, NO, NULL) autorelease]) == NULL) { cdvjk_encode_error(encodeState, @"Unable to create NSString object"); } }
- break;
-
- default: cdvjk_encode_error(encodeState, @"Unknown encode as type."); break;
- }
-
- if((returnObject != NULL) && (stackBuffer == NO)) { encodeState->stringBuffer.flags &= ~CDVJKManagedBufferMustFree; encodeState->stringBuffer.bytes.ptr = NULL; encodeState->stringBuffer.bytes.length = 0UL; }
- }
-
-errorExit:
- if((encodeState != NULL) && (error != NULL) && (encodeState->error != NULL)) { *error = encodeState->error; encodeState->error = NULL; }
- [self releaseState];
-
- return(returnObject);
-}
-
-- (void)releaseState
-{
- if(encodeState != NULL) {
- cdvjk_managedBuffer_release(&encodeState->stringBuffer);
- cdvjk_managedBuffer_release(&encodeState->utf8ConversionBuffer);
- free(encodeState); encodeState = NULL;
- }
-}
-
-- (void)dealloc
-{
- [self releaseState];
- [super dealloc];
-}
-
-@end
-
-@implementation NSString (CDVJSONKitSerializing)
-
-////////////
-#pragma mark Methods for serializing a single NSString.
-////////////
-
-// Useful for those who need to serialize just a NSString. Otherwise you would have to do something like [NSArray arrayWithObject:stringToBeJSONSerialized], serializing the array, and then chopping of the extra ^\[.*\]$ square brackets.
-
-// NSData returning methods...
-
-- (NSData *)cdvjk_JSONData
-{
- return([self cdvjk_JSONDataWithOptions:CDVJKSerializeOptionNone includeQuotes:YES error:NULL]);
-}
-
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsData | ((includeQuotes == NO) ? CDVJKEncodeOptionStringObjTrimQuotes : 0UL) | CDVJKEncodeOptionStringObj) block:NULL delegate:NULL selector:NULL error:error]);
-}
-
-// NSString returning methods...
-
-- (NSString *)cdvjk_JSONString
-{
- return([self cdvjk_JSONStringWithOptions:CDVJKSerializeOptionNone includeQuotes:YES error:NULL]);
-}
-
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsString | ((includeQuotes == NO) ? CDVJKEncodeOptionStringObjTrimQuotes : 0UL) | CDVJKEncodeOptionStringObj) block:NULL delegate:NULL selector:NULL error:error]);
-}
-
-@end
-
-@implementation NSArray (CDVJSONKitSerializing)
-
-// NSData returning methods...
-
-- (NSData *)cdvjk_JSONData
-{
- return([CDVJKSerializer serializeObject:self options:CDVJKSerializeOptionNone encodeOption:(CDVJKEncodeOptionAsData | CDVJKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:NULL]);
-}
-
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsData | CDVJKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:error]);
-}
-
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsData | CDVJKEncodeOptionCollectionObj) block:NULL delegate:delegate selector:selector error:error]);
-}
-
-// NSString returning methods...
-
-- (NSString *)cdvjk_JSONString
-{
- return([CDVJKSerializer serializeObject:self options:CDVJKSerializeOptionNone encodeOption:(CDVJKEncodeOptionAsString | CDVJKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:NULL]);
-}
-
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsString | CDVJKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:error]);
-}
-
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsString | CDVJKEncodeOptionCollectionObj) block:NULL delegate:delegate selector:selector error:error]);
-}
-
-@end
-
-@implementation NSDictionary (CDVJSONKitSerializing)
-
-// NSData returning methods...
-
-- (NSData *)cdvjk_JSONData
-{
- return([CDVJKSerializer serializeObject:self options:CDVJKSerializeOptionNone encodeOption:(CDVJKEncodeOptionAsData | CDVJKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:NULL]);
-}
-
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsData | CDVJKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:error]);
-}
-
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsData | CDVJKEncodeOptionCollectionObj) block:NULL delegate:delegate selector:selector error:error]);
-}
-
-// NSString returning methods...
-
-- (NSString *)cdvjk_JSONString
-{
- return([CDVJKSerializer serializeObject:self options:CDVJKSerializeOptionNone encodeOption:(CDVJKEncodeOptionAsString | CDVJKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:NULL]);
-}
-
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsString | CDVJKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:error]);
-}
-
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsString | CDVJKEncodeOptionCollectionObj) block:NULL delegate:delegate selector:selector error:error]);
-}
-
-@end
-
-
-#ifdef __BLOCKS__
-
-@implementation NSArray (CDVJSONKitSerializingBlockAdditions)
-
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsData | CDVJKEncodeOptionCollectionObj) block:block delegate:NULL selector:NULL error:error]);
-}
-
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsString | CDVJKEncodeOptionCollectionObj) block:block delegate:NULL selector:NULL error:error]);
-}
-
-@end
-
-@implementation NSDictionary (CDVJSONKitSerializingBlockAdditions)
-
-- (NSData *)cdvjk_JSONDataWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsData | CDVJKEncodeOptionCollectionObj) block:block delegate:NULL selector:NULL error:error]);
-}
-
-- (NSString *)cdvjk_JSONStringWithOptions:(CDVJKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error
-{
- return([CDVJKSerializer serializeObject:self options:serializeOptions encodeOption:(CDVJKEncodeOptionAsString | CDVJKEncodeOptionCollectionObj) block:block delegate:NULL selector:NULL error:error]);
-}
-
-@end
-
-#endif // __BLOCKS__
-
diff --git a/iPhone/CordovaLib/CordovaLib.xcodeproj/project.pbxproj b/iPhone/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
index 1bb7fa7..4868020 100755
--- a/iPhone/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
+++ b/iPhone/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
@@ -27,8 +27,6 @@
3073E9ED1656D51200957977 /* CDVScreenOrientationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 3073E9EC1656D51200957977 /* CDVScreenOrientationDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
307A8F9E1385A2EC00E43782 /* CDVConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 307A8F9C1385A2EC00E43782 /* CDVConnection.h */; settings = {ATTRIBUTES = (Public, ); }; };
307A8F9F1385A2EC00E43782 /* CDVConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 307A8F9D1385A2EC00E43782 /* CDVConnection.m */; };
- 30A90B9114588697006178D3 /* JSONKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A90B8F14588697006178D3 /* JSONKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 30A90B9314588697006178D3 /* JSONKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A90B9014588697006178D3 /* JSONKit.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
30B39EBE13D0268B0009682A /* CDVSplashScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 30B39EBC13D0268B0009682A /* CDVSplashScreen.h */; settings = {ATTRIBUTES = (Public, ); }; };
30B39EBF13D0268B0009682A /* CDVSplashScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 30B39EBD13D0268B0009682A /* CDVSplashScreen.m */; };
30C5F1DF15AF9E950052A00D /* CDVDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C5F1DD15AF9E950052A00D /* CDVDevice.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -41,13 +39,13 @@
30E33AF313A7E24B00594D64 /* CDVPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 30E33AF113A7E24B00594D64 /* CDVPlugin.m */; };
30E563CF13E217EC00C949AA /* NSMutableArray+QueueAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E563CD13E217EC00C949AA /* NSMutableArray+QueueAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
30E563D013E217EC00C949AA /* NSMutableArray+QueueAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 30E563CE13E217EC00C949AA /* NSMutableArray+QueueAdditions.m */; };
+ 30F3930B169F839700B22307 /* CDVJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 30F39309169F839700B22307 /* CDVJSON.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 30F3930C169F839700B22307 /* CDVJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 30F3930A169F839700B22307 /* CDVJSON.m */; };
30F5EBAB14CA26E700987760 /* CDVCommandDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 30F5EBA914CA26E700987760 /* CDVCommandDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
3E76876D156A90EE00EB6FA3 /* CDVLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E76876B156A90EE00EB6FA3 /* CDVLogger.m */; };
3E76876F156A90EE00EB6FA3 /* CDVLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E76876C156A90EE00EB6FA3 /* CDVLogger.h */; settings = {ATTRIBUTES = (Public, ); }; };
8852C43A14B65FD800F0E735 /* CDVViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8852C43614B65FD800F0E735 /* CDVViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
8852C43C14B65FD800F0E735 /* CDVViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8852C43714B65FD800F0E735 /* CDVViewController.m */; };
- 8852C43F14B65FD800F0E735 /* CDVCordovaView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8852C43814B65FD800F0E735 /* CDVCordovaView.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 8852C44114B65FD800F0E735 /* CDVCordovaView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8852C43914B65FD800F0E735 /* CDVCordovaView.m */; };
8887FD661090FBE7009987E8 /* CDVCamera.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD261090FBE7009987E8 /* CDVCamera.h */; settings = {ATTRIBUTES = (Public, ); }; };
8887FD671090FBE7009987E8 /* CDVCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD271090FBE7009987E8 /* CDVCamera.m */; };
8887FD681090FBE7009987E8 /* NSDictionary+Extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD281090FBE7009987E8 /* NSDictionary+Extensions.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -82,9 +80,13 @@
EB3B357D161F2A45003DBE7D /* CDVCommandDelegateImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = EB3B357B161F2A45003DBE7D /* CDVCommandDelegateImpl.m */; };
EB80C2AC15DEA63D004D9E7B /* CDVEcho.h in Headers */ = {isa = PBXBuildFile; fileRef = EB80C2AA15DEA63D004D9E7B /* CDVEcho.h */; settings = {ATTRIBUTES = (Public, ); }; };
EB80C2AD15DEA63D004D9E7B /* CDVEcho.m in Sources */ = {isa = PBXBuildFile; fileRef = EB80C2AB15DEA63D004D9E7B /* CDVEcho.m */; };
+ EB96673B16A8970A00D86CDF /* CDVUserAgentUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = EB96673916A8970900D86CDF /* CDVUserAgentUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ EB96673C16A8970A00D86CDF /* CDVUserAgentUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = EB96673A16A8970900D86CDF /* CDVUserAgentUtil.m */; };
EBA3557315ABD38C00F4DE24 /* NSArray+Comparisons.h in Headers */ = {isa = PBXBuildFile; fileRef = EBA3557115ABD38C00F4DE24 /* NSArray+Comparisons.h */; settings = {ATTRIBUTES = (Public, ); }; };
EBA3557515ABD38C00F4DE24 /* NSArray+Comparisons.m in Sources */ = {isa = PBXBuildFile; fileRef = EBA3557215ABD38C00F4DE24 /* NSArray+Comparisons.m */; };
- F858FBC6166009A8007DA594 /* CDVConfigParser.h in Headers */ = {isa = PBXBuildFile; fileRef = F858FBC4166009A8007DA594 /* CDVConfigParser.h */; };
+ EBFF4DBC16D3FE2E008F452B /* CDVWebViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = EBFF4DBA16D3FE2E008F452B /* CDVWebViewDelegate.m */; };
+ EBFF4DBD16D3FE2E008F452B /* CDVWebViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = EBFF4DBB16D3FE2E008F452B /* CDVWebViewDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F858FBC6166009A8007DA594 /* CDVConfigParser.h in Headers */ = {isa = PBXBuildFile; fileRef = F858FBC4166009A8007DA594 /* CDVConfigParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
F858FBC7166009A8007DA594 /* CDVConfigParser.m in Sources */ = {isa = PBXBuildFile; fileRef = F858FBC5166009A8007DA594 /* CDVConfigParser.m */; };
/* End PBXBuildFile section */
@@ -110,8 +112,6 @@
3073E9EC1656D51200957977 /* CDVScreenOrientationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVScreenOrientationDelegate.h; path = Classes/CDVScreenOrientationDelegate.h; sourceTree = "<group>"; };
307A8F9C1385A2EC00E43782 /* CDVConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVConnection.h; path = Classes/CDVConnection.h; sourceTree = "<group>"; };
307A8F9D1385A2EC00E43782 /* CDVConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVConnection.m; path = Classes/CDVConnection.m; sourceTree = "<group>"; };
- 30A90B8F14588697006178D3 /* JSONKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONKit.h; sourceTree = "<group>"; };
- 30A90B9014588697006178D3 /* JSONKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONKit.m; sourceTree = "<group>"; };
30B39EBC13D0268B0009682A /* CDVSplashScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVSplashScreen.h; path = Classes/CDVSplashScreen.h; sourceTree = "<group>"; };
30B39EBD13D0268B0009682A /* CDVSplashScreen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVSplashScreen.m; path = Classes/CDVSplashScreen.m; sourceTree = "<group>"; };
30C5F1DD15AF9E950052A00D /* CDVDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVDevice.h; path = Classes/CDVDevice.h; sourceTree = "<group>"; };
@@ -124,6 +124,8 @@
30E33AF113A7E24B00594D64 /* CDVPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVPlugin.m; path = Classes/CDVPlugin.m; sourceTree = "<group>"; };
30E563CD13E217EC00C949AA /* NSMutableArray+QueueAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSMutableArray+QueueAdditions.h"; path = "Classes/NSMutableArray+QueueAdditions.h"; sourceTree = "<group>"; };
30E563CE13E217EC00C949AA /* NSMutableArray+QueueAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSMutableArray+QueueAdditions.m"; path = "Classes/NSMutableArray+QueueAdditions.m"; sourceTree = "<group>"; };
+ 30F39309169F839700B22307 /* CDVJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVJSON.h; path = Classes/CDVJSON.h; sourceTree = "<group>"; };
+ 30F3930A169F839700B22307 /* CDVJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVJSON.m; path = Classes/CDVJSON.m; sourceTree = "<group>"; };
30F5EBA914CA26E700987760 /* CDVCommandDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVCommandDelegate.h; path = Classes/CDVCommandDelegate.h; sourceTree = "<group>"; };
3E76876B156A90EE00EB6FA3 /* CDVLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVLogger.m; path = Classes/CDVLogger.m; sourceTree = "<group>"; };
3E76876C156A90EE00EB6FA3 /* CDVLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVLogger.h; path = Classes/CDVLogger.h; sourceTree = "<group>"; };
@@ -141,8 +143,6 @@
68A32D7414103017006B237C /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; };
8852C43614B65FD800F0E735 /* CDVViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVViewController.h; path = Classes/CDVViewController.h; sourceTree = "<group>"; };
8852C43714B65FD800F0E735 /* CDVViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVViewController.m; path = Classes/CDVViewController.m; sourceTree = "<group>"; };
- 8852C43814B65FD800F0E735 /* CDVCordovaView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVCordovaView.h; path = Classes/CDVCordovaView.h; sourceTree = "<group>"; };
- 8852C43914B65FD800F0E735 /* CDVCordovaView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVCordovaView.m; path = Classes/CDVCordovaView.m; sourceTree = "<group>"; };
8887FD261090FBE7009987E8 /* CDVCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVCamera.h; path = Classes/CDVCamera.h; sourceTree = "<group>"; };
8887FD271090FBE7009987E8 /* CDVCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVCamera.m; path = Classes/CDVCamera.m; sourceTree = "<group>"; };
8887FD281090FBE7009987E8 /* NSDictionary+Extensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Extensions.h"; path = "Classes/NSDictionary+Extensions.h"; sourceTree = "<group>"; };
@@ -178,8 +178,12 @@
EB3B357B161F2A45003DBE7D /* CDVCommandDelegateImpl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVCommandDelegateImpl.m; path = Classes/CDVCommandDelegateImpl.m; sourceTree = "<group>"; };
EB80C2AA15DEA63D004D9E7B /* CDVEcho.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVEcho.h; path = Classes/CDVEcho.h; sourceTree = "<group>"; };
EB80C2AB15DEA63D004D9E7B /* CDVEcho.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVEcho.m; path = Classes/CDVEcho.m; sourceTree = "<group>"; };
+ EB96673916A8970900D86CDF /* CDVUserAgentUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVUserAgentUtil.h; path = Classes/CDVUserAgentUtil.h; sourceTree = "<group>"; };
+ EB96673A16A8970900D86CDF /* CDVUserAgentUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVUserAgentUtil.m; path = Classes/CDVUserAgentUtil.m; sourceTree = "<group>"; };
EBA3557115ABD38C00F4DE24 /* NSArray+Comparisons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSArray+Comparisons.h"; path = "Classes/NSArray+Comparisons.h"; sourceTree = "<group>"; };
EBA3557215ABD38C00F4DE24 /* NSArray+Comparisons.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSArray+Comparisons.m"; path = "Classes/NSArray+Comparisons.m"; sourceTree = "<group>"; };
+ EBFF4DBA16D3FE2E008F452B /* CDVWebViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVWebViewDelegate.m; path = Classes/CDVWebViewDelegate.m; sourceTree = "<group>"; };
+ EBFF4DBB16D3FE2E008F452B /* CDVWebViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVWebViewDelegate.h; path = Classes/CDVWebViewDelegate.h; sourceTree = "<group>"; };
F858FBC4166009A8007DA594 /* CDVConfigParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVConfigParser.h; path = Classes/CDVConfigParser.h; sourceTree = "<group>"; };
F858FBC5166009A8007DA594 /* CDVConfigParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVConfigParser.m; path = Classes/CDVConfigParser.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -240,8 +244,6 @@
F858FBC5166009A8007DA594 /* CDVConfigParser.m */,
8852C43614B65FD800F0E735 /* CDVViewController.h */,
8852C43714B65FD800F0E735 /* CDVViewController.m */,
- 8852C43814B65FD800F0E735 /* CDVCordovaView.h */,
- 8852C43914B65FD800F0E735 /* CDVCordovaView.m */,
EB3B3545161CB44D003DBE7D /* CDVCommandQueue.h */,
EB3B3546161CB44D003DBE7D /* CDVCommandQueue.m */,
);
@@ -259,6 +261,8 @@
888700D710922F56009987E8 /* Commands */ = {
isa = PBXGroup;
children = (
+ EBFF4DBA16D3FE2E008F452B /* CDVWebViewDelegate.m */,
+ EBFF4DBB16D3FE2E008F452B /* CDVWebViewDelegate.h */,
30C5F1DD15AF9E950052A00D /* CDVDevice.h */,
30C5F1DE15AF9E950052A00D /* CDVDevice.m */,
301F2F2914F3C9CA003FE9FC /* CDV.h */,
@@ -317,6 +321,10 @@
3073E9E71656D37700957977 /* CDVInAppBrowser.h */,
3073E9E81656D37700957977 /* CDVInAppBrowser.m */,
3073E9EC1656D51200957977 /* CDVScreenOrientationDelegate.h */,
+ 30F39309169F839700B22307 /* CDVJSON.h */,
+ 30F3930A169F839700B22307 /* CDVJSON.m */,
+ EB96673916A8970900D86CDF /* CDVUserAgentUtil.h */,
+ EB96673A16A8970900D86CDF /* CDVUserAgentUtil.m */,
);
name = Commands;
sourceTree = "<group>";
@@ -344,22 +352,11 @@
children = (
3054098714B77FF3009841CA /* Cleaver */,
888700D710922F56009987E8 /* Commands */,
- 8887FD361090FBE7009987E8 /* JSON */,
888700D910923009009987E8 /* Util */,
);
name = Classes;
sourceTree = "<group>";
};
- 8887FD361090FBE7009987E8 /* JSON */ = {
- isa = PBXGroup;
- children = (
- 30A90B8F14588697006178D3 /* JSONKit.h */,
- 30A90B9014588697006178D3 /* JSONKit.m */,
- );
- name = JSON;
- path = Classes/JSON;
- sourceTree = "<group>";
- };
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -391,9 +388,7 @@
1F2BECC013F9785B00A93BF6 /* CDVBattery.h in Headers */,
30C684801406CB38004C1A8E /* CDVWhitelist.h in Headers */,
30C684941407044B004C1A8E /* CDVURLProtocol.h in Headers */,
- 30A90B9114588697006178D3 /* JSONKit.h in Headers */,
8852C43A14B65FD800F0E735 /* CDVViewController.h in Headers */,
- 8852C43F14B65FD800F0E735 /* CDVCordovaView.h in Headers */,
30F5EBAB14CA26E700987760 /* CDVCommandDelegate.h in Headers */,
301F2F2A14F3C9CA003FE9FC /* CDV.h in Headers */,
30392E4E14F4FCAB00B9E0B8 /* CDVAvailability.h in Headers */,
@@ -409,6 +404,9 @@
3073E9E91656D37700957977 /* CDVInAppBrowser.h in Headers */,
3073E9ED1656D51200957977 /* CDVScreenOrientationDelegate.h in Headers */,
F858FBC6166009A8007DA594 /* CDVConfigParser.h in Headers */,
+ 30F3930B169F839700B22307 /* CDVJSON.h in Headers */,
+ EBFF4DBD16D3FE2E008F452B /* CDVWebViewDelegate.h in Headers */,
+ EB96673B16A8970A00D86CDF /* CDVUserAgentUtil.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -438,7 +436,7 @@
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0430;
+ LastUpgradeCheck = 0460;
};
buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "CordovaLib" */;
compatibilityVersion = "Xcode 3.2";
@@ -489,9 +487,7 @@
1F2BECC113F9785B00A93BF6 /* CDVBattery.m in Sources */,
30C684821406CB38004C1A8E /* CDVWhitelist.m in Sources */,
30C684961407044B004C1A8E /* CDVURLProtocol.m in Sources */,
- 30A90B9314588697006178D3 /* JSONKit.m in Sources */,
8852C43C14B65FD800F0E735 /* CDVViewController.m in Sources */,
- 8852C44114B65FD800F0E735 /* CDVCordovaView.m in Sources */,
3034979E1513D56A0090E688 /* CDVLocalStorage.m in Sources */,
3062D122151D0EDB000D9128 /* UIDevice+Extensions.m in Sources */,
3E76876D156A90EE00EB6FA3 /* CDVLogger.m in Sources */,
@@ -503,6 +499,9 @@
9D76CF3D1625A4C50008A0F6 /* CDVGlobalization.m in Sources */,
3073E9EA1656D37700957977 /* CDVInAppBrowser.m in Sources */,
F858FBC7166009A8007DA594 /* CDVConfigParser.m in Sources */,
+ 30F3930C169F839700B22307 /* CDVJSON.m in Sources */,
+ EB96673C16A8970A00D86CDF /* CDVUserAgentUtil.m in Sources */,
+ EBFF4DBC16D3FE2E008F452B /* CDVWebViewDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -573,12 +572,17 @@
armv7s,
);
"ARCHS[sdk=iphonesimulator*]" = i386;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "";
GCC_THUMB_SUPPORT = NO;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
ONLY_ACTIVE_ARCH = NO;
@@ -601,11 +605,16 @@
armv7s,
);
"ARCHS[sdk=iphonesimulator*]" = i386;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_PREPROCESSOR_DEFINITIONS = "";
GCC_THUMB_SUPPORT = NO;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
ONLY_ACTIVE_ARCH = NO;
diff --git a/iPhone/CordovaLib/CordovaLib.xcodeproj/xcuserdata/struan.xcuserdatad/xcschemes/xcschememanagement.plist b/iPhone/CordovaLib/CordovaLib.xcodeproj/xcuserdata/struan.xcuserdatad/xcschemes/xcschememanagement.plist
index 283503b..8672103 100644
--- a/iPhone/CordovaLib/CordovaLib.xcodeproj/xcuserdata/struan.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/iPhone/CordovaLib/CordovaLib.xcodeproj/xcuserdata/struan.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -7,7 +7,7 @@
<key>CordovaLib.xcscheme</key>
<dict>
<key>orderHint</key>
- <integer>1</integer>
+ <integer>2</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
diff --git a/iPhone/CordovaLib/VERSION b/iPhone/CordovaLib/VERSION
index cc6612c..437459c 100755
--- a/iPhone/CordovaLib/VERSION
+++ b/iPhone/CordovaLib/VERSION
@@ -1 +1 @@
-2.3.0 \ No newline at end of file
+2.5.0
diff --git a/iPhone/FixMyStreet.xcodeproj/project.pbxproj b/iPhone/FixMyStreet.xcodeproj/project.pbxproj
index 9c798f1..f42384a 100644
--- a/iPhone/FixMyStreet.xcodeproj/project.pbxproj
+++ b/iPhone/FixMyStreet.xcodeproj/project.pbxproj
@@ -13,6 +13,7 @@
1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
1F766FE113BBADB100FB74C0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1F766FDC13BBADB100FB74C0 /* Localizable.strings */; };
1F766FE213BBADB100FB74C0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1F766FDF13BBADB100FB74C0 /* Localizable.strings */; };
+ 246C8F801700A4010052666F /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 246C8F7F1700A4010052666F /* AssetsLibrary.framework */; };
288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; };
301BF552109A68D80062928A /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF535109A57CC0062928A /* libCordova.a */; };
301BF570109A69640062928A /* www in Resources */ = {isa = PBXBuildFile; fileRef = 301BF56E109A69640062928A /* www */; };
@@ -63,6 +64,7 @@
1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
1F766FDD13BBADB100FB74C0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Localizable.strings; sourceTree = "<group>"; };
1F766FE013BBADB100FB74C0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = Localizable.strings; sourceTree = "<group>"; };
+ 246C8F7F1700A4010052666F /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = CordovaLib/CordovaLib.xcodeproj; sourceTree = "<group>"; };
@@ -104,6 +106,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 246C8F801700A4010052666F /* AssetsLibrary.framework in Frameworks */,
301BF552109A68D80062928A /* libCordova.a in Frameworks */,
1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,
1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */,
@@ -165,6 +168,7 @@
29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
isa = PBXGroup;
children = (
+ 246C8F7F1700A4010052666F /* AssetsLibrary.framework */,
F840E1F0165FE0F500CFE078 /* config.xml */,
301BF56E109A69640062928A /* www */,
301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */,
@@ -309,7 +313,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0430;
+ LastUpgradeCheck = 0460;
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "FixMyStreet" */;
compatibilityVersion = "Xcode 3.2";
@@ -450,7 +454,6 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_OBJC_ARC = NO;
- CLANG_WARN_OBJCPP_ARC_ABI = YES;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
@@ -470,7 +473,6 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_OBJC_ARC = NO;
- CLANG_WARN_OBJCPP_ARC_ABI = YES;
COPY_PHASE_STRIP = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "FixMyStreet/FixMyStreet-Prefix.pch";
@@ -487,11 +489,16 @@
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_THUMB_SUPPORT = NO;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"",
@@ -522,11 +529,16 @@
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_THUMB_SUPPORT = NO;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"",
diff --git a/iPhone/FixMyStreet/Classes/AppDelegate.m b/iPhone/FixMyStreet/Classes/AppDelegate.m
index 7d6bcd8..77e991d 100644
--- a/iPhone/FixMyStreet/Classes/AppDelegate.m
+++ b/iPhone/FixMyStreet/Classes/AppDelegate.m
@@ -43,6 +43,11 @@
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
+ int cacheSizeMemory = 8 * 1024 * 1024; // 8MB
+ int cacheSizeDisk = 32 * 1024 * 1024; // 32MB
+ NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
+ [NSURLCache setSharedURLCache:sharedCache];
+
self = [super init];
return self;
}
@@ -109,4 +114,9 @@
return supportedInterfaceOrientations;
}
+- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application
+{
+ [[NSURLCache sharedURLCache] removeAllCachedResponses];
+}
+
@end
diff --git a/iPhone/FixMyStreet/config.xml b/iPhone/FixMyStreet/config.xml
index 7ea9bb5..9798f07 100644
--- a/iPhone/FixMyStreet/config.xml
+++ b/iPhone/FixMyStreet/config.xml
@@ -1,12 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
-<cordova>
+<widget>
<preference name="AllowInlineMediaPlayback" value="false"/>
<preference name="AutoHideSplashScreen" value="true"/>
<preference name="EnableLocation" value="false"/>
<preference name="EnableViewportScale" value="false"/>
<preference name="MediaPlaybackRequiresUserAction" value="false"/>
- <preference name="OpenAllWhitelistURLsInWebView" value="false"/>
<preference name="ShowSplashScreenSpinner" value="true"/>
+ <preference name="FadeSplashScreen" value="true" />
+ <preference name="FadeSplashScreenDuration" value="2" />
<preference name="TopActivityIndicator" value="gray"/>
<preference name="UIWebViewBounce" value="true"/>
<content src="index.html" />
@@ -32,4 +33,4 @@
<access origin="*.virtualearth.net"/>
<access origin="mapit.mysociety.org"/>
<access origin="struan.fixmystreet.dev.mysociety.org"/>
-</cordova>
+</widget>
diff --git a/iPhone/cordova/build b/iPhone/cordova/build
new file mode 100755
index 0000000..1574c5e
--- /dev/null
+++ b/iPhone/cordova/build
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+#
+# 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.
+#
+
+#
+# compile and launch a Cordova/iOS project to the simulator
+#
+
+set -e
+
+XCODE_VER=$(xcodebuild -version | head -n 1 | sed -e 's/Xcode //')
+XCODE_MIN_VERSION="4.5"
+
+if [[ "$XCODE_VER" < "$XCODE_MIN_VERSION" ]]; then
+ echo "Cordova can only run in Xcode version $XCODE_MIN_VERSION or greater."
+ exit 1
+fi
+
+CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P)
+PROJECT_PATH="$(dirname "$CORDOVA_PATH")"
+XCODEPROJ=$( ls "$PROJECT_PATH" | grep .xcodeproj )
+PROJECT_NAME=$(basename "$XCODEPROJ" .xcodeproj)
+
+cd "$PROJECT_PATH"
+
+APP=build/$PROJECT_NAME.app
+SDK=`xcodebuild -showsdks | grep Sim | tail -1 | awk '{print $6}'`
+
+xcodebuild -project $PROJECT_NAME.xcodeproj -arch i386 -target $PROJECT_NAME -configuration Debug -sdk $SDK clean build VALID_ARCHS="i386" CONFIGURATION_BUILD_DIR="$PROJECT_PATH/build"
+
+
+
+
+
diff --git a/iPhone/cordova/emulate b/iPhone/cordova/emulate
new file mode 100755
index 0000000..f26cb3a
--- /dev/null
+++ b/iPhone/cordova/emulate
@@ -0,0 +1,55 @@
+#! /bin/bash
+#
+# 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.
+#
+
+set -e
+
+XCODE_VER=$(xcodebuild -version | head -n 1 | sed -e 's/Xcode //')
+XCODE_MIN_VERSION="4.5"
+
+if [[ "$XCODE_VER" < "$XCODE_MIN_VERSION" ]]; then
+ echo "Cordova can only run in Xcode version $XCODE_MIN_VERSION or greater."
+ exit 1
+fi
+
+CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P)
+PROJECT_PATH="$(dirname "$CORDOVA_PATH")"
+XCODEPROJ=$( ls "$PROJECT_PATH" | grep .xcodeproj )
+PROJECT_NAME=$(basename "$XCODEPROJ" .xcodeproj)
+
+APP_PATH=${1:-$PROJECT_PATH/build/$PROJECT_NAME.app}
+DEVICE_FAMILY=${2:-${DEVICE_FAMILY:-iphone}}
+
+if [ ! -d "$APP_PATH" ]; then
+ echo "Project '$APP_PATH' is not built. Building."
+ $CORDOVA_PATH/build || exit $?
+fi
+
+if [ ! -d "$APP_PATH" ]; then
+ echo "$APP_PATH not found to emulate."
+ exit 1
+fi
+
+# launch using ios-sim
+if which ios-sim >/dev/null; then
+ ios-sim launch "$APP_PATH" --family "$DEVICE_FAMILY" --stderr "$CORDOVA_PATH/console.log" --stdout "$CORDOVA_PATH/console.log" &
+else
+ echo -e '\033[31mError: ios-sim was not found. Please download, build and install version 1.4 or greater from https://github.com/phonegap/ios-sim into your path. Or "brew install ios-sim" using homebrew: http://mxcl.github.com/homebrew/\033[m'; exit 1;
+fi
+
diff --git a/iPhone/cordova/log b/iPhone/cordova/log
new file mode 100755
index 0000000..b235b09
--- /dev/null
+++ b/iPhone/cordova/log
@@ -0,0 +1,23 @@
+#! /bin/sh
+#
+# 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.
+#
+
+CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P)
+
+tail -f "$CORDOVA_PATH/console.log"
diff --git a/iPhone/cordova/release b/iPhone/cordova/release
new file mode 100755
index 0000000..7263934
--- /dev/null
+++ b/iPhone/cordova/release
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+#
+# 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.
+#
+
+#
+# compile and launch a Cordova/iOS project to the simulator
+#
+
+set -e
+
+XCODE_VER=$(xcodebuild -version | head -n 1 | sed -e 's/Xcode //')
+XCODE_MIN_VERSION="4.5"
+
+if [[ "$XCODE_VER" < "$XCODE_MIN_VERSION" ]]; then
+ echo "Cordova can only run in Xcode version $XCODE_MIN_VERSION or greater."
+ exit 1
+fi
+
+CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P)
+PROJECT_PATH="$(dirname "$CORDOVA_PATH")"
+XCODEPROJ=$( ls "$PROJECT_PATH" | grep .xcodeproj )
+PROJECT_NAME=$(basename "$XCODEPROJ" .xcodeproj)
+
+cd "$PROJECT_PATH"
+
+APP=build/$PROJECT_NAME.app
+SDK=`xcodebuild -showsdks | grep Sim | tail -1 | awk '{print $6}'`
+
+xcodebuild -project $PROJECT_NAME.xcodeproj -arch i386 -target $PROJECT_NAME -configuration Release -sdk $SDK clean build VALID_ARCHS="i386" CONFIGURATION_BUILD_DIR="$PROJECT_PATH/build"
+
+
+
+
+
diff --git a/iPhone/cordova/run b/iPhone/cordova/run
new file mode 100755
index 0000000..ef7198e
--- /dev/null
+++ b/iPhone/cordova/run
@@ -0,0 +1,58 @@
+#! /bin/sh
+#
+# 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.
+#
+
+set -e
+
+XCODE_VER=$(xcodebuild -version | head -n 1 | sed -e 's/Xcode //')
+XCODE_MIN_VERSION="4.5"
+
+if [[ "$XCODE_VER" < "$XCODE_MIN_VERSION" ]]; then
+ echo "Cordova can only run in Xcode version $XCODE_MIN_VERSION or greater."
+ exit 1
+fi
+
+CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P)
+PROJECT_PATH="$(dirname "$CORDOVA_PATH")"
+XCODEPROJ=$( ls "$PROJECT_PATH" | grep .xcodeproj )
+PROJECT_NAME=$(basename "$XCODEPROJ" .xcodeproj)
+
+APP_PATH=$1
+
+if [ $# -lt 1 ]; then
+ APP_PATH="$PROJECT_PATH/build/$PROJECT_NAME.app"
+fi
+
+if [ ! -d "$APP_PATH" ]; then
+ echo "Project '$APP_PATH' is not built. Building."
+ $CORDOVA_PATH/build || exit $?
+fi
+
+if [ ! -d "$APP_PATH" ]; then
+ echo "$APP_PATH not found to emulate."
+ exit 1
+fi
+
+# launch using ios-sim
+if which ios-sim >/dev/null; then
+ ios-sim launch "$APP_PATH" --stderr "$CORDOVA_PATH/console.log" --stdout "$CORDOVA_PATH/console.log" &
+else
+ echo -e '\033[31mError: ios-sim was not found. Please download, build and install version 1.4 or greater from https://github.com/phonegap/ios-sim into your path. Or "brew install ios-sim" using homebrew: http://mxcl.github.com/homebrew/\033[m'; exit 1;
+fi
+
diff --git a/www/cordova-independent.js b/www/cordova-independent.js
index c6dde34..6590173 100644
--- a/www/cordova-independent.js
+++ b/www/cordova-independent.js
@@ -2,7 +2,7 @@
var scriptElement = document.createElement("script");
scriptElement.type = "text/javascript";
if (navigator.userAgent.match(/(iPhone|iPod|iPad)/)) {
- scriptElement.src = 'cordova-ios-2.4.0.js';
+ scriptElement.src = 'cordova-ios-2.5.0.js';
} else if (navigator.userAgent.match(/Android/)) {
scriptElement.src = 'cordova-android-2.2.0.js';
} else {
diff --git a/www/cordova-ios-2.5.0.js b/www/cordova-ios-2.5.0.js
new file mode 100755
index 0000000..3d83df3
--- /dev/null
+++ b/www/cordova-ios-2.5.0.js
@@ -0,0 +1,6083 @@
+// Platform: ios
+
+// commit f50d20a87431c79a54572263729461883f611a53
+
+// File generated at :: Tue Feb 26 2013 14:26:19 GMT-0800 (PST)
+
+/*
+ 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.
+*/
+
+;(function() {
+
+// file: lib/scripts/require.js
+
+var require,
+ define;
+
+(function () {
+ var modules = {};
+ // Stack of moduleIds currently being built.
+ var requireStack = [];
+ // Map of module ID -> index into requireStack of modules currently being built.
+ var inProgressModules = {};
+
+ function build(module) {
+ var factory = module.factory;
+ module.exports = {};
+ delete module.factory;
+ factory(require, module.exports, module);
+ return module.exports;
+ }
+
+ require = function (id) {
+ if (!modules[id]) {
+ throw "module " + id + " not found";
+ } else if (id in inProgressModules) {
+ var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+ throw "Cycle in require graph: " + cycle;
+ }
+ if (modules[id].factory) {
+ try {
+ inProgressModules[id] = requireStack.length;
+ requireStack.push(id);
+ return build(modules[id]);
+ } finally {
+ delete inProgressModules[id];
+ requireStack.pop();
+ }
+ }
+ return modules[id].exports;
+ };
+
+ define = function (id, factory) {
+ if (modules[id]) {
+ throw "module " + id + " already defined";
+ }
+
+ modules[id] = {
+ id: id,
+ factory: factory
+ };
+ };
+
+ define.remove = function (id) {
+ delete modules[id];
+ };
+
+ define.moduleMap = modules;
+})();
+
+//Export for use in node
+if (typeof module === "object" && typeof require === "function") {
+ module.exports.require = require;
+ module.exports.define = define;
+}
+
+// file: lib/cordova.js
+define("cordova", function(require, exports, module) {
+
+
+var channel = require('cordova/channel');
+
+/**
+ * Listen for DOMContentLoaded and notify our channel subscribers.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+ channel.onDOMContentLoaded.fire();
+}, false);
+if (document.readyState == 'complete' || document.readyState == 'interactive') {
+ channel.onDOMContentLoaded.fire();
+}
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {},
+ windowEventHandlers = {};
+
+document.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ if (typeof documentEventHandlers[e] != 'undefined') {
+ documentEventHandlers[e].subscribe(handler);
+ } else {
+ m_document_addEventListener.call(document, evt, handler, capture);
+ }
+};
+
+window.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ if (typeof windowEventHandlers[e] != 'undefined') {
+ windowEventHandlers[e].subscribe(handler);
+ } else {
+ m_window_addEventListener.call(window, evt, handler, capture);
+ }
+};
+
+document.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ // If unsubscribing from an event that is handled by a plugin
+ if (typeof documentEventHandlers[e] != "undefined") {
+ documentEventHandlers[e].unsubscribe(handler);
+ } else {
+ m_document_removeEventListener.call(document, evt, handler, capture);
+ }
+};
+
+window.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ // If unsubscribing from an event that is handled by a plugin
+ if (typeof windowEventHandlers[e] != "undefined") {
+ windowEventHandlers[e].unsubscribe(handler);
+ } else {
+ m_window_removeEventListener.call(window, evt, handler, capture);
+ }
+};
+
+function createEvent(type, data) {
+ var event = document.createEvent('Events');
+ event.initEvent(type, false, false);
+ if (data) {
+ for (var i in data) {
+ if (data.hasOwnProperty(i)) {
+ event[i] = data[i];
+ }
+ }
+ }
+ return event;
+}
+
+if(typeof window.console === "undefined") {
+ window.console = {
+ log:function(){}
+ };
+}
+
+var cordova = {
+ define:define,
+ require:require,
+ /**
+ * Methods to add/remove your own addEventListener hijacking on document + window.
+ */
+ addWindowEventHandler:function(event) {
+ return (windowEventHandlers[event] = channel.create(event));
+ },
+ addStickyDocumentEventHandler:function(event) {
+ return (documentEventHandlers[event] = channel.createSticky(event));
+ },
+ addDocumentEventHandler:function(event) {
+ return (documentEventHandlers[event] = channel.create(event));
+ },
+ removeWindowEventHandler:function(event) {
+ delete windowEventHandlers[event];
+ },
+ removeDocumentEventHandler:function(event) {
+ delete documentEventHandlers[event];
+ },
+ /**
+ * Retrieve original event handlers that were replaced by Cordova
+ *
+ * @return object
+ */
+ getOriginalHandlers: function() {
+ return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+ 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+ },
+ /**
+ * Method to fire event from native code
+ * bNoDetach is required for events which cause an exception which needs to be caught in native code
+ */
+ fireDocumentEvent: function(type, data, bNoDetach) {
+ var evt = createEvent(type, data);
+ if (typeof documentEventHandlers[type] != 'undefined') {
+ if( bNoDetach ) {
+ documentEventHandlers[type].fire(evt);
+ }
+ else {
+ setTimeout(function() {
+ documentEventHandlers[type].fire(evt);
+ }, 0);
+ }
+ } else {
+ document.dispatchEvent(evt);
+ }
+ },
+ fireWindowEvent: function(type, data) {
+ var evt = createEvent(type,data);
+ if (typeof windowEventHandlers[type] != 'undefined') {
+ setTimeout(function() {
+ windowEventHandlers[type].fire(evt);
+ }, 0);
+ } else {
+ window.dispatchEvent(evt);
+ }
+ },
+
+ /**
+ * Plugin callback mechanism.
+ */
+ // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+ // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+ callbackId: Math.floor(Math.random() * 2000000000),
+ callbacks: {},
+ callbackStatus: {
+ NO_RESULT: 0,
+ OK: 1,
+ CLASS_NOT_FOUND_EXCEPTION: 2,
+ ILLEGAL_ACCESS_EXCEPTION: 3,
+ INSTANTIATION_EXCEPTION: 4,
+ MALFORMED_URL_EXCEPTION: 5,
+ IO_EXCEPTION: 6,
+ INVALID_ACTION: 7,
+ JSON_EXCEPTION: 8,
+ ERROR: 9
+ },
+
+ /**
+ * Called by native code when returning successful result from an action.
+ */
+ callbackSuccess: function(callbackId, args) {
+ try {
+ cordova.callbackFromNative(callbackId, true, args.status, args.message, args.keepCallback);
+ } catch (e) {
+ console.log("Error in error callback: " + callbackId + " = "+e);
+ }
+ },
+
+ /**
+ * Called by native code when returning error result from an action.
+ */
+ callbackError: function(callbackId, args) {
+ // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+ // Derive success from status.
+ try {
+ cordova.callbackFromNative(callbackId, false, args.status, args.message, args.keepCallback);
+ } catch (e) {
+ console.log("Error in error callback: " + callbackId + " = "+e);
+ }
+ },
+
+ /**
+ * Called by native code when returning the result from an action.
+ */
+ callbackFromNative: function(callbackId, success, status, message, keepCallback) {
+ var callback = cordova.callbacks[callbackId];
+ if (callback) {
+ if (success && status == cordova.callbackStatus.OK) {
+ callback.success && callback.success(message);
+ } else if (!success) {
+ callback.fail && callback.fail(message);
+ }
+
+ // Clear callback if not expecting any more results
+ if (!keepCallback) {
+ delete cordova.callbacks[callbackId];
+ }
+ }
+ },
+ addConstructor: function(func) {
+ channel.onCordovaReady.subscribe(function() {
+ try {
+ func();
+ } catch(e) {
+ console.log("Failed to run constructor: " + e);
+ }
+ });
+ }
+};
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+module.exports = cordova;
+
+});
+
+// file: lib/common/argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+ 'A': 'Array',
+ 'D': 'Date',
+ 'N': 'Number',
+ 'S': 'String',
+ 'F': 'Function',
+ 'O': 'Object'
+};
+
+function extractParamName(callee, argIndex) {
+ return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs(spec, functionName, args, opt_callee) {
+ if (!moduleExports.enableChecks) {
+ return;
+ }
+ var errMsg = null;
+ var typeName;
+ for (var i = 0; i < spec.length; ++i) {
+ var c = spec.charAt(i),
+ cUpper = c.toUpperCase(),
+ arg = args[i];
+ // Asterix means allow anything.
+ if (c == '*') {
+ continue;
+ }
+ typeName = utils.typeName(arg);
+ if ((arg === null || arg === undefined) && c == cUpper) {
+ continue;
+ }
+ if (typeName != typeMap[cUpper]) {
+ errMsg = 'Expected ' + typeMap[cUpper];
+ break;
+ }
+ }
+ if (errMsg) {
+ errMsg += ', but got ' + typeName + '.';
+ errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+ // Don't log when running jake test.
+ if (typeof jasmine == 'undefined') {
+ console.error(errMsg);
+ }
+ throw TypeError(errMsg);
+ }
+}
+
+function getValue(value, defaultValue) {
+ return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+
+});
+
+// file: lib/common/builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each(objects, func, context) {
+ for (var prop in objects) {
+ if (objects.hasOwnProperty(prop)) {
+ func.apply(context, [objects[prop], prop]);
+ }
+ }
+}
+
+function clobber(obj, key, value) {
+ exports.replaceHookForTesting(obj, key);
+ obj[key] = value;
+ // Getters can only be overridden by getters.
+ if (obj[key] !== value) {
+ utils.defineGetter(obj, key, function() {
+ return value;
+ });
+ }
+}
+
+function assignOrWrapInDeprecateGetter(obj, key, value, message) {
+ if (message) {
+ utils.defineGetter(obj, key, function() {
+ console.log(message);
+ delete obj[key];
+ clobber(obj, key, value);
+ return value;
+ });
+ } else {
+ clobber(obj, key, value);
+ }
+}
+
+function include(parent, objects, clobber, merge) {
+ each(objects, function (obj, key) {
+ try {
+ var result = obj.path ? require(obj.path) : {};
+
+ if (clobber) {
+ // Clobber if it doesn't exist.
+ if (typeof parent[key] === 'undefined') {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ } else if (typeof obj.path !== 'undefined') {
+ // If merging, merge properties onto parent, otherwise, clobber.
+ if (merge) {
+ recursiveMerge(parent[key], result);
+ } else {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ }
+ }
+ result = parent[key];
+ } else {
+ // Overwrite if not currently defined.
+ if (typeof parent[key] == 'undefined') {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ } else {
+ // Set result to what already exists, so we can build children into it if they exist.
+ result = parent[key];
+ }
+ }
+
+ if (obj.children) {
+ include(result, obj.children, clobber, merge);
+ }
+ } catch(e) {
+ utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
+ }
+ });
+}
+
+/**
+ * Merge properties from one object onto another recursively. Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge(target, src) {
+ for (var prop in src) {
+ if (src.hasOwnProperty(prop)) {
+ if (target.prototype && target.prototype.constructor === target) {
+ // If the target object is a constructor override off prototype.
+ clobber(target.prototype, prop, src[prop]);
+ } else {
+ if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+ recursiveMerge(target[prop], src[prop]);
+ } else {
+ clobber(target, prop, src[prop]);
+ }
+ }
+ }
+ }
+}
+
+exports.buildIntoButDoNotClobber = function(objects, target) {
+ include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function(objects, target) {
+ include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+ include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
+
+});
+
+// file: lib/common/channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady* Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created.
+ * onCordovaInfoReady* Internal event fired when device properties are available.
+ * onCordovaConnectionReady* Internal event fired when the connection property has been set.
+ * onDeviceReady* User event fired to indicate that Cordova is ready
+ * onResume User event fired to indicate a start/resume lifecycle event
+ * onPause User event fired to indicate a pause lifecycle event
+ * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ * pause App has moved to background
+ * resume App has returned to foreground
+ *
+ * Listeners can be registered as:
+ * document.addEventListener("deviceready", myDeviceReadyListener, false);
+ * document.addEventListener("resume", myResumeListener, false);
+ * document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ * window.onload
+ * window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type String the channel name
+ */
+var Channel = function(type, sticky) {
+ this.type = type;
+ // Map of guid -> function.
+ this.handlers = {};
+ // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+ this.state = sticky ? 1 : 0;
+ // Used in sticky mode to remember args passed to fire().
+ this.fireArgs = null;
+ // Used by onHasSubscribersChange to know if there are any listeners.
+ this.numHandlers = 0;
+ // Function that is called when the first listener is subscribed, or when
+ // the last listener is unsubscribed.
+ this.onHasSubscribersChange = null;
+},
+ channel = {
+ /**
+ * Calls the provided function only after all of the channels specified
+ * have been fired. All channels must be sticky channels.
+ */
+ join: function(h, c) {
+ var len = c.length,
+ i = len,
+ f = function() {
+ if (!(--i)) h();
+ };
+ for (var j=0; j<len; j++) {
+ if (c[j].state === 0) {
+ throw Error('Can only use join with sticky channels.');
+ }
+ c[j].subscribe(f);
+ }
+ if (!len) h();
+ },
+ create: function(type) {
+ return channel[type] = new Channel(type, false);
+ },
+ createSticky: function(type) {
+ return channel[type] = new Channel(type, true);
+ },
+
+ /**
+ * cordova Channels that must fire before "deviceready" is fired.
+ */
+ deviceReadyChannelsArray: [],
+ deviceReadyChannelsMap: {},
+
+ /**
+ * Indicate that a feature needs to be initialized before it is ready to be used.
+ * This holds up Cordova's "deviceready" event until the feature has been initialized
+ * and Cordova.initComplete(feature) is called.
+ *
+ * @param feature {String} The unique feature name
+ */
+ waitForInitialization: function(feature) {
+ if (feature) {
+ var c = channel[feature] || this.createSticky(feature);
+ this.deviceReadyChannelsMap[feature] = c;
+ this.deviceReadyChannelsArray.push(c);
+ }
+ },
+
+ /**
+ * Indicate that initialization code has completed and the feature is ready to be used.
+ *
+ * @param feature {String} The unique feature name
+ */
+ initializationComplete: function(feature) {
+ var c = this.deviceReadyChannelsMap[feature];
+ if (c) {
+ c.fire();
+ }
+ }
+ };
+
+function forceFunction(f) {
+ if (typeof f != 'function') throw "Function required as first argument!";
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function(f, c) {
+ // need a function to call
+ forceFunction(f);
+ if (this.state == 2) {
+ f.apply(c || this, this.fireArgs);
+ return;
+ }
+
+ var func = f,
+ guid = f.observer_guid;
+ if (typeof c == "object") { func = utils.close(c, f); }
+
+ if (!guid) {
+ // first time any channel has seen this subscriber
+ guid = '' + nextGuid++;
+ }
+ func.observer_guid = guid;
+ f.observer_guid = guid;
+
+ // Don't add the same handler more than once.
+ if (!this.handlers[guid]) {
+ this.handlers[guid] = func;
+ this.numHandlers++;
+ if (this.numHandlers == 1) {
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function(f) {
+ // need a function to unsubscribe
+ forceFunction(f);
+
+ var guid = f.observer_guid,
+ handler = this.handlers[guid];
+ if (handler) {
+ delete this.handlers[guid];
+ this.numHandlers--;
+ if (this.numHandlers === 0) {
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function(e) {
+ var fail = false,
+ fireArgs = Array.prototype.slice.call(arguments);
+ // Apply stickiness.
+ if (this.state == 1) {
+ this.state = 2;
+ this.fireArgs = fireArgs;
+ }
+ if (this.numHandlers) {
+ // Copy the values first so that it is safe to modify it from within
+ // callbacks.
+ var toCall = [];
+ for (var item in this.handlers) {
+ toCall.push(this.handlers[item]);
+ }
+ for (var i = 0; i < toCall.length; ++i) {
+ toCall[i].apply(this, fireArgs);
+ }
+ if (this.state == 2 && this.numHandlers) {
+ this.numHandlers = 0;
+ this.handlers = {};
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that device properties are available
+channel.createSticky('onCordovaInfoReady');
+
+// Event to indicate that the connection property has been set.
+channel.createSticky('onCordovaConnectionReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Event to indicate a destroy lifecycle event
+channel.createSticky('onDestroy');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onCordovaConnectionReady');
+
+module.exports = channel;
+
+});
+
+// file: lib/common/commandProxy.js
+define("cordova/commandProxy", function(require, exports, module) {
+
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+ // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+ add:function(id,proxyObj) {
+ console.log("adding proxy for " + id);
+ CommandProxyMap[id] = proxyObj;
+ return proxyObj;
+ },
+
+ // cordova.commandProxy.remove("Accelerometer");
+ remove:function(id) {
+ var proxy = CommandProxyMap[id];
+ delete CommandProxyMap[id];
+ CommandProxyMap[id] = null;
+ return proxy;
+ },
+
+ get:function(service,action) {
+ return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
+ }
+};
+});
+
+// file: lib/ios/exec.js
+define("cordova/exec", function(require, exports, module) {
+
+/**
+ * Creates a gap bridge iframe used to notify the native code about queued
+ * commands.
+ *
+ * @private
+ */
+var cordova = require('cordova'),
+ channel = require('cordova/channel'),
+ utils = require('cordova/utils'),
+ jsToNativeModes = {
+ IFRAME_NAV: 0,
+ XHR_NO_PAYLOAD: 1,
+ XHR_WITH_PAYLOAD: 2,
+ XHR_OPTIONAL_PAYLOAD: 3
+ },
+ bridgeMode,
+ execIframe,
+ execXhr,
+ requestCount = 0,
+ vcHeaderValue = null,
+ commandQueue = [], // Contains pending JS->Native messages.
+ isInContextOfEvalJs = 0;
+
+function createExecIframe() {
+ var iframe = document.createElement("iframe");
+ iframe.style.display = 'none';
+ document.body.appendChild(iframe);
+ return iframe;
+}
+
+function shouldBundleCommandJson() {
+ if (bridgeMode == jsToNativeModes.XHR_WITH_PAYLOAD) {
+ return true;
+ }
+ if (bridgeMode == jsToNativeModes.XHR_OPTIONAL_PAYLOAD) {
+ var payloadLength = 0;
+ for (var i = 0; i < commandQueue.length; ++i) {
+ payloadLength += commandQueue[i].length;
+ }
+ // The value here was determined using the benchmark within CordovaLibApp on an iPad 3.
+ return payloadLength < 4500;
+ }
+ return false;
+}
+
+function massageArgsJsToNative(args) {
+ if (!args || utils.typeName(args) != 'Array') {
+ return args;
+ }
+ var encodeArrayBufferAs8bitString = function(ab) {
+ return String.fromCharCode.apply(null, new Uint8Array(ab));
+ };
+ var encodeArrayBufferAsBase64 = function(ab) {
+ return window.btoa(encodeArrayBufferAs8bitString(ab));
+ };
+ args.forEach(function(arg, i) {
+ if (utils.typeName(arg) == 'ArrayBuffer') {
+ args[i] = {
+ 'CDVType': 'ArrayBuffer',
+ 'data': encodeArrayBufferAsBase64(arg)
+ };
+ }
+ });
+ return args;
+}
+
+function massagePayloadNativeToJs(payload) {
+ if (payload && payload.hasOwnProperty('CDVType') && payload.CDVType == 'ArrayBuffer') {
+ var stringToArrayBuffer = function(str) {
+ var ret = new Uint8Array(str.length);
+ for (var i = 0; i < str.length; i++) {
+ ret[i] = str.charCodeAt(i);
+ }
+ return ret.buffer;
+ };
+ var base64ToArrayBuffer = function(b64) {
+ return stringToArrayBuffer(atob(b64));
+ };
+ payload = base64ToArrayBuffer(payload.data);
+ }
+ return payload;
+}
+
+function iOSExec() {
+ // XHR mode does not work on iOS 4.2, so default to IFRAME_NAV for such devices.
+ // XHR mode's main advantage is working around a bug in -webkit-scroll, which
+ // doesn't exist in 4.X devices anyways.
+ if (bridgeMode === undefined) {
+ bridgeMode = navigator.userAgent.indexOf(' 4_') == -1 ? jsToNativeModes.XHR_NO_PAYLOAD : jsToNativeModes.IFRAME_NAV;
+ }
+
+ var successCallback, failCallback, service, action, actionArgs, splitCommand;
+ var callbackId = null;
+ if (typeof arguments[0] !== "string") {
+ // FORMAT ONE
+ successCallback = arguments[0];
+ failCallback = arguments[1];
+ service = arguments[2];
+ action = arguments[3];
+ actionArgs = arguments[4];
+
+ // Since we need to maintain backwards compatibility, we have to pass
+ // an invalid callbackId even if no callback was provided since plugins
+ // will be expecting it. The Cordova.exec() implementation allocates
+ // an invalid callbackId and passes it even if no callbacks were given.
+ callbackId = 'INVALID';
+ } else {
+ // FORMAT TWO
+ splitCommand = arguments[0].split(".");
+ action = splitCommand.pop();
+ service = splitCommand.join(".");
+ actionArgs = Array.prototype.splice.call(arguments, 1);
+ }
+
+ // Register the callbacks and add the callbackId to the positional
+ // arguments if given.
+ if (successCallback || failCallback) {
+ callbackId = service + cordova.callbackId++;
+ cordova.callbacks[callbackId] =
+ {success:successCallback, fail:failCallback};
+ }
+
+ actionArgs = massageArgsJsToNative(actionArgs);
+
+ var command = [callbackId, service, action, actionArgs];
+
+ // Stringify and queue the command. We stringify to command now to
+ // effectively clone the command arguments in case they are mutated before
+ // the command is executed.
+ commandQueue.push(JSON.stringify(command));
+
+ // If we're in the context of a stringByEvaluatingJavaScriptFromString call,
+ // then the queue will be flushed when it returns; no need for a poke.
+ // Also, if there is already a command in the queue, then we've already
+ // poked the native side, so there is no reason to do so again.
+ if (!isInContextOfEvalJs && commandQueue.length == 1) {
+ if (bridgeMode != jsToNativeModes.IFRAME_NAV) {
+ // This prevents sending an XHR when there is already one being sent.
+ // This should happen only in rare circumstances (refer to unit tests).
+ if (execXhr && execXhr.readyState != 4) {
+ execXhr = null;
+ }
+ // Re-using the XHR improves exec() performance by about 10%.
+ execXhr = execXhr || new XMLHttpRequest();
+ // Changing this to a GET will make the XHR reach the URIProtocol on 4.2.
+ // For some reason it still doesn't work though...
+ // Add a timestamp to the query param to prevent caching.
+ execXhr.open('HEAD', "/!gap_exec?" + (+new Date()), true);
+ if (!vcHeaderValue) {
+ vcHeaderValue = /.*\((.*)\)/.exec(navigator.userAgent)[1];
+ }
+ execXhr.setRequestHeader('vc', vcHeaderValue);
+ execXhr.setRequestHeader('rc', ++requestCount);
+ if (shouldBundleCommandJson()) {
+ execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages());
+ }
+ execXhr.send(null);
+ } else {
+ execIframe = execIframe || createExecIframe();
+ execIframe.src = "gap://ready";
+ }
+ }
+}
+
+iOSExec.jsToNativeModes = jsToNativeModes;
+
+iOSExec.setJsToNativeBridgeMode = function(mode) {
+ // Remove the iFrame since it may be no longer required, and its existence
+ // can trigger browser bugs.
+ // https://issues.apache.org/jira/browse/CB-593
+ if (execIframe) {
+ execIframe.parentNode.removeChild(execIframe);
+ execIframe = null;
+ }
+ bridgeMode = mode;
+};
+
+iOSExec.nativeFetchMessages = function() {
+ // Each entry in commandQueue is a JSON string already.
+ if (!commandQueue.length) {
+ return '';
+ }
+ var json = '[' + commandQueue.join(',') + ']';
+ commandQueue.length = 0;
+ return json;
+};
+
+iOSExec.nativeCallback = function(callbackId, status, payload, keepCallback) {
+ return iOSExec.nativeEvalAndFetch(function() {
+ var success = status === 0 || status === 1;
+ payload = massagePayloadNativeToJs(payload);
+ cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
+ });
+};
+
+iOSExec.nativeEvalAndFetch = function(func) {
+ // This shouldn't be nested, but better to be safe.
+ isInContextOfEvalJs++;
+ try {
+ func();
+ return iOSExec.nativeFetchMessages();
+ } finally {
+ isInContextOfEvalJs--;
+ }
+};
+
+module.exports = iOSExec;
+
+});
+
+// file: lib/common/modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder'),
+ moduleMap = define.moduleMap,
+ symbolList,
+ deprecationMap;
+
+exports.reset = function() {
+ symbolList = [];
+ deprecationMap = {};
+};
+
+function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
+ if (!(moduleName in moduleMap)) {
+ throw new Error('Module ' + moduleName + ' does not exist.');
+ }
+ symbolList.push(strategy, moduleName, symbolPath);
+ if (opt_deprecationMessage) {
+ deprecationMap[symbolPath] = opt_deprecationMessage;
+ }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+function prepareNamespace(symbolPath, context) {
+ if (!symbolPath) {
+ return context;
+ }
+ var parts = symbolPath.split('.');
+ var cur = context;
+ for (var i = 0, part; part = parts[i]; ++i) {
+ cur = cur[part] = cur[part] || {};
+ }
+ return cur;
+}
+
+exports.mapModules = function(context) {
+ var origSymbols = {};
+ context.CDV_origSymbols = origSymbols;
+ for (var i = 0, len = symbolList.length; i < len; i += 3) {
+ var strategy = symbolList[i];
+ var moduleName = symbolList[i + 1];
+ var symbolPath = symbolList[i + 2];
+ var lastDot = symbolPath.lastIndexOf('.');
+ var namespace = symbolPath.substr(0, lastDot);
+ var lastName = symbolPath.substr(lastDot + 1);
+
+ var module = require(moduleName);
+ var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+ var parentObj = prepareNamespace(namespace, context);
+ var target = parentObj[lastName];
+
+ if (strategy == 'm' && target) {
+ builder.recursiveMerge(target, module);
+ } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
+ if (!(symbolPath in origSymbols)) {
+ origSymbols[symbolPath] = target;
+ }
+ builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+ }
+ }
+};
+
+exports.getOriginalSymbol = function(context, symbolPath) {
+ var origSymbols = context.CDV_origSymbols;
+ if (origSymbols && (symbolPath in origSymbols)) {
+ return origSymbols[symbolPath];
+ }
+ var parts = symbolPath.split('.');
+ var obj = context;
+ for (var i = 0; i < parts.length; ++i) {
+ obj = obj && obj[parts[i]];
+ }
+ return obj;
+};
+
+exports.loadMatchingModules = function(matchingRegExp) {
+ for (var k in moduleMap) {
+ if (matchingRegExp.exec(k)) {
+ require(k);
+ }
+ }
+};
+
+exports.reset();
+
+
+});
+
+// file: lib/ios/platform.js
+define("cordova/platform", function(require, exports, module) {
+
+module.exports = {
+ id: "ios",
+ initialize:function() {
+ var modulemapper = require('cordova/modulemapper');
+
+ modulemapper.loadMatchingModules(/cordova.*\/plugininit$/);
+
+ modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
+ modulemapper.mapModules(window);
+ }
+};
+
+
+});
+
+// file: lib/common/plugin/Acceleration.js
+define("cordova/plugin/Acceleration", function(require, exports, module) {
+
+var Acceleration = function(x, y, z, timestamp) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.timestamp = timestamp || (new Date()).getTime();
+};
+
+module.exports = Acceleration;
+
+});
+
+// file: lib/common/plugin/Camera.js
+define("cordova/plugin/Camera", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ Camera = require('cordova/plugin/CameraConstants'),
+ CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle');
+
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+ cameraExport[key] = Camera[key];
+}
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
+ *
+ * @param {Function} successCallback
+ * @param {Function} errorCallback
+ * @param {Object} options
+ */
+cameraExport.getPicture = function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+ options = options || {};
+ var getValue = argscheck.getValue;
+
+ var quality = getValue(options.quality, 50);
+ var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+ var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+ var targetWidth = getValue(options.targetWidth, -1);
+ var targetHeight = getValue(options.targetHeight, -1);
+ var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+ var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+ var allowEdit = !!options.allowEdit;
+ var correctOrientation = !!options.correctOrientation;
+ var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+ var popoverOptions = getValue(options.popoverOptions, null);
+
+ var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+ mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions];
+
+ exec(successCallback, errorCallback, "Camera", "takePicture", args);
+ return new CameraPopoverHandle();
+};
+
+cameraExport.cleanup = function(successCallback, errorCallback) {
+ exec(successCallback, errorCallback, "Camera", "cleanup", []);
+};
+
+module.exports = cameraExport;
+
+});
+
+// file: lib/common/plugin/CameraConstants.js
+define("cordova/plugin/CameraConstants", function(require, exports, module) {
+
+module.exports = {
+ DestinationType:{
+ DATA_URL: 0, // Return base64 encoded string
+ FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android)
+ NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS)
+ },
+ EncodingType:{
+ JPEG: 0, // Return JPEG encoded image
+ PNG: 1 // Return PNG encoded image
+ },
+ MediaType:{
+ PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+ VIDEO: 1, // allow selection of video only, ONLY RETURNS URL
+ ALLMEDIA : 2 // allow selection from all media types
+ },
+ PictureSourceType:{
+ PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+ CAMERA : 1, // Take picture from camera
+ SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android)
+ },
+ PopoverArrowDirection:{
+ ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
+ ARROW_DOWN : 2,
+ ARROW_LEFT : 4,
+ ARROW_RIGHT : 8,
+ ARROW_ANY : 15
+ }
+};
+
+});
+
+// file: lib/ios/plugin/CameraPopoverHandle.js
+define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function() {
+ this.setPosition = function(popoverOptions) {
+ var args = [ popoverOptions ];
+ exec(null, null, "Camera", "repositionPopover", args);
+ };
+};
+
+module.exports = CameraPopoverHandle;
+
+});
+
+// file: lib/common/plugin/CameraPopoverOptions.js
+define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) {
+
+var Camera = require('cordova/plugin/CameraConstants');
+
+/**
+ * Encapsulates options for iOS Popover image picker
+ */
+var CameraPopoverOptions = function(x,y,width,height,arrowDir){
+ // information of rectangle that popover should be anchored to
+ this.x = x || 0;
+ this.y = y || 32;
+ this.width = width || 320;
+ this.height = height || 480;
+ // The direction of the popover arrow
+ this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;
+
+});
+
+// file: lib/common/plugin/CaptureAudioOptions.js
+define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all audio capture operation configuration options.
+ */
+var CaptureAudioOptions = function(){
+ // Upper limit of sound clips user can record. Value must be equal or greater than 1.
+ this.limit = 1;
+ // Maximum duration of a single sound clip in seconds.
+ this.duration = 0;
+ // The selected audio mode. Must match with one of the elements in supportedAudioModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureAudioOptions;
+
+});
+
+// file: lib/common/plugin/CaptureError.js
+define("cordova/plugin/CaptureError", function(require, exports, module) {
+
+/**
+ * The CaptureError interface encapsulates all errors in the Capture API.
+ */
+var CaptureError = function(c) {
+ this.code = c || null;
+};
+
+// Camera or microphone failed to capture image or sound.
+CaptureError.CAPTURE_INTERNAL_ERR = 0;
+// Camera application or audio capture application is currently serving other capture request.
+CaptureError.CAPTURE_APPLICATION_BUSY = 1;
+// Invalid use of the API (e.g. limit parameter has value less than one).
+CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
+// User exited camera application or audio capture application before capturing anything.
+CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
+// The requested capture operation is not supported.
+CaptureError.CAPTURE_NOT_SUPPORTED = 20;
+
+module.exports = CaptureError;
+
+});
+
+// file: lib/common/plugin/CaptureImageOptions.js
+define("cordova/plugin/CaptureImageOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all image capture operation configuration options.
+ */
+var CaptureImageOptions = function(){
+ // Upper limit of images user can take. Value must be equal or greater than 1.
+ this.limit = 1;
+ // The selected image mode. Must match with one of the elements in supportedImageModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureImageOptions;
+
+});
+
+// file: lib/common/plugin/CaptureVideoOptions.js
+define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all video capture operation configuration options.
+ */
+var CaptureVideoOptions = function(){
+ // Upper limit of videos user can record. Value must be equal or greater than 1.
+ this.limit = 1;
+ // Maximum duration of a single video clip in seconds.
+ this.duration = 0;
+ // The selected video mode. Must match with one of the elements in supportedVideoModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureVideoOptions;
+
+});
+
+// file: lib/common/plugin/CompassError.js
+define("cordova/plugin/CompassError", function(require, exports, module) {
+
+/**
+ * CompassError.
+ * An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var CompassError = function(err) {
+ this.code = (err !== undefined ? err : null);
+};
+
+CompassError.COMPASS_INTERNAL_ERR = 0;
+CompassError.COMPASS_NOT_SUPPORTED = 20;
+
+module.exports = CompassError;
+
+});
+
+// file: lib/common/plugin/CompassHeading.js
+define("cordova/plugin/CompassHeading", function(require, exports, module) {
+
+var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
+ this.magneticHeading = magneticHeading;
+ this.trueHeading = trueHeading;
+ this.headingAccuracy = headingAccuracy;
+ this.timestamp = timestamp || new Date().getTime();
+};
+
+module.exports = CompassHeading;
+
+});
+
+// file: lib/common/plugin/ConfigurationData.js
+define("cordova/plugin/ConfigurationData", function(require, exports, module) {
+
+/**
+ * Encapsulates a set of parameters that the capture device supports.
+ */
+function ConfigurationData() {
+ // The ASCII-encoded string in lower case representing the media type.
+ this.type = null;
+ // The height attribute represents height of the image or video in pixels.
+ // In the case of a sound clip this attribute has value 0.
+ this.height = 0;
+ // The width attribute represents width of the image or video in pixels.
+ // In the case of a sound clip this attribute has value 0
+ this.width = 0;
+}
+
+module.exports = ConfigurationData;
+
+});
+
+// file: lib/common/plugin/Connection.js
+define("cordova/plugin/Connection", function(require, exports, module) {
+
+/**
+ * Network status
+ */
+module.exports = {
+ UNKNOWN: "unknown",
+ ETHERNET: "ethernet",
+ WIFI: "wifi",
+ CELL_2G: "2g",
+ CELL_3G: "3g",
+ CELL_4G: "4g",
+ CELL:"cellular",
+ NONE: "none"
+};
+
+});
+
+// file: lib/common/plugin/Contact.js
+define("cordova/plugin/Contact", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ ContactError = require('cordova/plugin/ContactError'),
+ utils = require('cordova/utils');
+
+/**
+* Converts primitives into Complex Object
+* Currently only used for Date fields
+*/
+function convertIn(contact) {
+ var value = contact.birthday;
+ try {
+ contact.birthday = new Date(parseFloat(value));
+ } catch (exception){
+ console.log("Cordova Contact convertIn error: exception creating date.");
+ }
+ return contact;
+}
+
+/**
+* Converts Complex objects into primitives
+* Only conversion at present is for Dates.
+**/
+
+function convertOut(contact) {
+ var value = contact.birthday;
+ if (value !== null) {
+ // try to make it a Date object if it is not already
+ if (!utils.isDate(value)){
+ try {
+ value = new Date(value);
+ } catch(exception){
+ value = null;
+ }
+ }
+ if (utils.isDate(value)){
+ value = value.valueOf(); // convert to milliseconds
+ }
+ contact.birthday = value;
+ }
+ return contact;
+}
+
+/**
+* Contains information about a single contact.
+* @constructor
+* @param {DOMString} id unique identifier
+* @param {DOMString} displayName
+* @param {ContactName} name
+* @param {DOMString} nickname
+* @param {Array.<ContactField>} phoneNumbers array of phone numbers
+* @param {Array.<ContactField>} emails array of email addresses
+* @param {Array.<ContactAddress>} addresses array of addresses
+* @param {Array.<ContactField>} ims instant messaging user ids
+* @param {Array.<ContactOrganization>} organizations
+* @param {DOMString} birthday contact's birthday
+* @param {DOMString} note user notes about contact
+* @param {Array.<ContactField>} photos
+* @param {Array.<ContactField>} categories
+* @param {Array.<ContactField>} urls contact's web sites
+*/
+var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
+ ims, organizations, birthday, note, photos, categories, urls) {
+ this.id = id || null;
+ this.rawId = null;
+ this.displayName = displayName || null;
+ this.name = name || null; // ContactName
+ this.nickname = nickname || null;
+ this.phoneNumbers = phoneNumbers || null; // ContactField[]
+ this.emails = emails || null; // ContactField[]
+ this.addresses = addresses || null; // ContactAddress[]
+ this.ims = ims || null; // ContactField[]
+ this.organizations = organizations || null; // ContactOrganization[]
+ this.birthday = birthday || null;
+ this.note = note || null;
+ this.photos = photos || null; // ContactField[]
+ this.categories = categories || null; // ContactField[]
+ this.urls = urls || null; // ContactField[]
+};
+
+/**
+* Removes contact from device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.remove = function(successCB, errorCB) {
+ argscheck.checkArgs('FF', 'Contact.remove', arguments);
+ var fail = errorCB && function(code) {
+ errorCB(new ContactError(code));
+ };
+ if (this.id === null) {
+ fail(ContactError.UNKNOWN_ERROR);
+ }
+ else {
+ exec(successCB, fail, "Contacts", "remove", [this.id]);
+ }
+};
+
+/**
+* Creates a deep copy of this Contact.
+* With the contact ID set to null.
+* @return copy of this Contact
+*/
+Contact.prototype.clone = function() {
+ var clonedContact = utils.clone(this);
+ clonedContact.id = null;
+ clonedContact.rawId = null;
+
+ function nullIds(arr) {
+ if (arr) {
+ for (var i = 0; i < arr.length; ++i) {
+ arr[i].id = null;
+ }
+ }
+ }
+
+ // Loop through and clear out any id's in phones, emails, etc.
+ nullIds(clonedContact.phoneNumbers);
+ nullIds(clonedContact.emails);
+ nullIds(clonedContact.addresses);
+ nullIds(clonedContact.ims);
+ nullIds(clonedContact.organizations);
+ nullIds(clonedContact.categories);
+ nullIds(clonedContact.photos);
+ nullIds(clonedContact.urls);
+ return clonedContact;
+};
+
+/**
+* Persists contact to device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.save = function(successCB, errorCB) {
+ argscheck.checkArgs('FFO', 'Contact.save', arguments);
+ var fail = errorCB && function(code) {
+ errorCB(new ContactError(code));
+ };
+ var success = function(result) {
+ if (result) {
+ if (successCB) {
+ var fullContact = require('cordova/plugin/contacts').create(result);
+ successCB(convertIn(fullContact));
+ }
+ }
+ else {
+ // no Entry object returned
+ fail(ContactError.UNKNOWN_ERROR);
+ }
+ };
+ var dupContact = convertOut(utils.clone(this));
+ exec(success, fail, "Contacts", "save", [dupContact]);
+};
+
+
+module.exports = Contact;
+
+});
+
+// file: lib/common/plugin/ContactAddress.js
+define("cordova/plugin/ContactAddress", function(require, exports, module) {
+
+/**
+* Contact address.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code
+* @param formatted // NOTE: not a W3C standard
+* @param streetAddress
+* @param locality
+* @param region
+* @param postalCode
+* @param country
+*/
+
+var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
+ this.id = null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+ this.type = type || null;
+ this.formatted = formatted || null;
+ this.streetAddress = streetAddress || null;
+ this.locality = locality || null;
+ this.region = region || null;
+ this.postalCode = postalCode || null;
+ this.country = country || null;
+};
+
+module.exports = ContactAddress;
+
+});
+
+// file: lib/common/plugin/ContactError.js
+define("cordova/plugin/ContactError", function(require, exports, module) {
+
+/**
+ * ContactError.
+ * An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var ContactError = function(err) {
+ this.code = (typeof err != 'undefined' ? err : null);
+};
+
+/**
+ * Error codes
+ */
+ContactError.UNKNOWN_ERROR = 0;
+ContactError.INVALID_ARGUMENT_ERROR = 1;
+ContactError.TIMEOUT_ERROR = 2;
+ContactError.PENDING_OPERATION_ERROR = 3;
+ContactError.IO_ERROR = 4;
+ContactError.NOT_SUPPORTED_ERROR = 5;
+ContactError.PERMISSION_DENIED_ERROR = 20;
+
+module.exports = ContactError;
+
+});
+
+// file: lib/common/plugin/ContactField.js
+define("cordova/plugin/ContactField", function(require, exports, module) {
+
+/**
+* Generic contact field.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param type
+* @param value
+* @param pref
+*/
+var ContactField = function(type, value, pref) {
+ this.id = null;
+ this.type = (type && type.toString()) || null;
+ this.value = (value && value.toString()) || null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+};
+
+module.exports = ContactField;
+
+});
+
+// file: lib/common/plugin/ContactFindOptions.js
+define("cordova/plugin/ContactFindOptions", function(require, exports, module) {
+
+/**
+ * ContactFindOptions.
+ * @constructor
+ * @param filter used to match contacts against
+ * @param multiple boolean used to determine if more than one contact should be returned
+ */
+
+var ContactFindOptions = function(filter, multiple) {
+ this.filter = filter || '';
+ this.multiple = (typeof multiple != 'undefined' ? multiple : false);
+};
+
+module.exports = ContactFindOptions;
+
+});
+
+// file: lib/common/plugin/ContactName.js
+define("cordova/plugin/ContactName", function(require, exports, module) {
+
+/**
+* Contact name.
+* @constructor
+* @param formatted // NOTE: not part of W3C standard
+* @param familyName
+* @param givenName
+* @param middle
+* @param prefix
+* @param suffix
+*/
+var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
+ this.formatted = formatted || null;
+ this.familyName = familyName || null;
+ this.givenName = givenName || null;
+ this.middleName = middle || null;
+ this.honorificPrefix = prefix || null;
+ this.honorificSuffix = suffix || null;
+};
+
+module.exports = ContactName;
+
+});
+
+// file: lib/common/plugin/ContactOrganization.js
+define("cordova/plugin/ContactOrganization", function(require, exports, module) {
+
+/**
+* Contact organization.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param name
+* @param dept
+* @param title
+* @param startDate
+* @param endDate
+* @param location
+* @param desc
+*/
+
+var ContactOrganization = function(pref, type, name, dept, title) {
+ this.id = null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+ this.type = type || null;
+ this.name = name || null;
+ this.department = dept || null;
+ this.title = title || null;
+};
+
+module.exports = ContactOrganization;
+
+});
+
+// file: lib/common/plugin/Coordinates.js
+define("cordova/plugin/Coordinates", function(require, exports, module) {
+
+/**
+ * This class contains position information.
+ * @param {Object} lat
+ * @param {Object} lng
+ * @param {Object} alt
+ * @param {Object} acc
+ * @param {Object} head
+ * @param {Object} vel
+ * @param {Object} altacc
+ * @constructor
+ */
+var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
+ /**
+ * The latitude of the position.
+ */
+ this.latitude = lat;
+ /**
+ * The longitude of the position,
+ */
+ this.longitude = lng;
+ /**
+ * The accuracy of the position.
+ */
+ this.accuracy = acc;
+ /**
+ * The altitude of the position.
+ */
+ this.altitude = (alt !== undefined ? alt : null);
+ /**
+ * The direction the device is moving at the position.
+ */
+ this.heading = (head !== undefined ? head : null);
+ /**
+ * The velocity with which the device is moving at the position.
+ */
+ this.speed = (vel !== undefined ? vel : null);
+
+ if (this.speed === 0 || this.speed === null) {
+ this.heading = NaN;
+ }
+
+ /**
+ * The altitude accuracy of the position.
+ */
+ this.altitudeAccuracy = (altacc !== undefined) ? altacc : null;
+};
+
+module.exports = Coordinates;
+
+});
+
+// file: lib/common/plugin/DirectoryEntry.js
+define("cordova/plugin/DirectoryEntry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ Entry = require('cordova/plugin/Entry'),
+ FileError = require('cordova/plugin/FileError'),
+ DirectoryReader = require('cordova/plugin/DirectoryReader');
+
+/**
+ * An interface representing a directory on the file system.
+ *
+ * {boolean} isFile always false (readonly)
+ * {boolean} isDirectory always true (readonly)
+ * {DOMString} name of the directory, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the directory (readonly)
+ * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly)
+ */
+var DirectoryEntry = function(name, fullPath) {
+ DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath);
+};
+
+utils.extend(DirectoryEntry, Entry);
+
+/**
+ * Creates a new DirectoryReader to read entries from this directory
+ */
+DirectoryEntry.prototype.createReader = function() {
+ return new DirectoryReader(this.fullPath);
+};
+
+/**
+ * Creates or looks up a directory
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
+ * @param {Flags} options to create or exclusively create the directory
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
+ argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
+ var win = successCallback && function(result) {
+ var entry = new DirectoryEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]);
+};
+
+/**
+ * Deletes a directory and all of it's contents
+ *
+ * @param {Function} successCallback is called with no parameters
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]);
+};
+
+/**
+ * Creates or looks up a file
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
+ * @param {Flags} options to create or exclusively create the file
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
+ argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
+ var win = successCallback && function(result) {
+ var FileEntry = require('cordova/plugin/FileEntry');
+ var entry = new FileEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getFile", [this.fullPath, path, options]);
+};
+
+module.exports = DirectoryEntry;
+
+});
+
+// file: lib/common/plugin/DirectoryReader.js
+define("cordova/plugin/DirectoryReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError') ;
+
+/**
+ * An interface that lists the files and directories in a directory.
+ */
+function DirectoryReader(path) {
+ this.path = path || null;
+}
+
+/**
+ * Returns a list of entries from a directory.
+ *
+ * @param {Function} successCallback is called with a list of entries
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
+ var win = typeof successCallback !== 'function' ? null : function(result) {
+ var retVal = [];
+ for (var i=0; i<result.length; i++) {
+ var entry = null;
+ if (result[i].isDirectory) {
+ entry = new (require('cordova/plugin/DirectoryEntry'))();
+ }
+ else if (result[i].isFile) {
+ entry = new (require('cordova/plugin/FileEntry'))();
+ }
+ entry.isDirectory = result[i].isDirectory;
+ entry.isFile = result[i].isFile;
+ entry.name = result[i].name;
+ entry.fullPath = result[i].fullPath;
+ retVal.push(entry);
+ }
+ successCallback(retVal);
+ };
+ var fail = typeof errorCallback !== 'function' ? null : function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "readEntries", [this.path]);
+};
+
+module.exports = DirectoryReader;
+
+});
+
+// file: lib/common/plugin/Entry.js
+define("cordova/plugin/Entry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError'),
+ Metadata = require('cordova/plugin/Metadata');
+
+/**
+ * Represents a file or directory on the local file system.
+ *
+ * @param isFile
+ * {boolean} true if Entry is a file (readonly)
+ * @param isDirectory
+ * {boolean} true if Entry is a directory (readonly)
+ * @param name
+ * {DOMString} name of the file or directory, excluding the path
+ * leading to it (readonly)
+ * @param fullPath
+ * {DOMString} the absolute full path to the file or directory
+ * (readonly)
+ */
+function Entry(isFile, isDirectory, name, fullPath, fileSystem) {
+ this.isFile = !!isFile;
+ this.isDirectory = !!isDirectory;
+ this.name = name || '';
+ this.fullPath = fullPath || '';
+ this.filesystem = fileSystem || null;
+}
+
+/**
+ * Look up the metadata of the entry.
+ *
+ * @param successCallback
+ * {Function} is called with a Metadata object
+ * @param errorCallback
+ * {Function} is called with a FileError
+ */
+Entry.prototype.getMetadata = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
+ var success = successCallback && function(lastModified) {
+ var metadata = new Metadata(lastModified);
+ successCallback(metadata);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+
+ exec(success, fail, "File", "getMetadata", [this.fullPath]);
+};
+
+/**
+ * Set the metadata of the entry.
+ *
+ * @param successCallback
+ * {Function} is called with a Metadata object
+ * @param errorCallback
+ * {Function} is called with a FileError
+ * @param metadataObject
+ * {Object} keys and values to set
+ */
+Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) {
+ argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
+ exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]);
+};
+
+/**
+ * Move a file or directory to a new location.
+ *
+ * @param parent
+ * {DirectoryEntry} the directory to which to move this entry
+ * @param newName
+ * {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ * {Function} called with the new DirectoryEntry object
+ * @param errorCallback
+ * {Function} called with a FileError
+ */
+Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
+ argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ // source path
+ var srcPath = this.fullPath,
+ // entry name
+ name = newName || this.name,
+ success = function(entry) {
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail && fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ // copy
+ exec(success, fail, "File", "moveTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Copy a directory to a different location.
+ *
+ * @param parent
+ * {DirectoryEntry} the directory to which to copy the entry
+ * @param newName
+ * {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ * {Function} called with the new Entry object
+ * @param errorCallback
+ * {Function} called with a FileError
+ */
+Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
+ argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+
+ // source path
+ var srcPath = this.fullPath,
+ // entry name
+ name = newName || this.name,
+ // success callback
+ success = function(entry) {
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail && fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ // copy
+ exec(success, fail, "File", "copyTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Return a URL that can be used to identify this entry.
+ */
+Entry.prototype.toURL = function() {
+ // fullPath attribute contains the full URL
+ return this.fullPath;
+};
+
+/**
+ * Returns a URI that can be used to identify this entry.
+ *
+ * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
+ * @return uri
+ */
+Entry.prototype.toURI = function(mimeType) {
+ console.log("DEPRECATED: Update your code to use 'toURL'");
+ // fullPath attribute contains the full URI
+ return this.toURL();
+};
+
+/**
+ * Remove a file or directory. It is an error to attempt to delete a
+ * directory that is not empty. It is an error to attempt to delete a
+ * root directory of a file system.
+ *
+ * @param successCallback {Function} called with no parameters
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.remove = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.remove', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(successCallback, fail, "File", "remove", [this.fullPath]);
+};
+
+/**
+ * Look up the parent DirectoryEntry of this entry.
+ *
+ * @param successCallback {Function} called with the parent DirectoryEntry object
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.getParent = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.getParent', arguments);
+ var win = successCallback && function(result) {
+ var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+ var entry = new DirectoryEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getParent", [this.fullPath]);
+};
+
+module.exports = Entry;
+
+});
+
+// file: lib/common/plugin/File.js
+define("cordova/plugin/File", function(require, exports, module) {
+
+/**
+ * Constructor.
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+
+var File = function(name, fullPath, type, lastModifiedDate, size){
+ this.name = name || '';
+ this.fullPath = fullPath || null;
+ this.type = type || null;
+ this.lastModifiedDate = lastModifiedDate || null;
+ this.size = size || 0;
+
+ // These store the absolute start and end for slicing the file.
+ this.start = 0;
+ this.end = this.size;
+};
+
+/**
+ * Returns a "slice" of the file. Since Cordova Files don't contain the actual
+ * content, this really returns a File with adjusted start and end.
+ * Slices of slices are supported.
+ * start {Number} The index at which to start the slice (inclusive).
+ * end {Number} The index at which to end the slice (exclusive).
+ */
+File.prototype.slice = function(start, end) {
+ var size = this.end - this.start;
+ var newStart = 0;
+ var newEnd = size;
+ if (arguments.length) {
+ if (start < 0) {
+ newStart = Math.max(size + start, 0);
+ } else {
+ newStart = Math.min(size, start);
+ }
+ }
+
+ if (arguments.length >= 2) {
+ if (end < 0) {
+ newEnd = Math.max(size + end, 0);
+ } else {
+ newEnd = Math.min(end, size);
+ }
+ }
+
+ var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size);
+ newFile.start = this.start + newStart;
+ newFile.end = this.start + newEnd;
+ return newFile;
+};
+
+
+module.exports = File;
+
+});
+
+// file: lib/common/plugin/FileEntry.js
+define("cordova/plugin/FileEntry", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ Entry = require('cordova/plugin/Entry'),
+ FileWriter = require('cordova/plugin/FileWriter'),
+ File = require('cordova/plugin/File'),
+ FileError = require('cordova/plugin/FileError');
+
+/**
+ * An interface representing a file on the file system.
+ *
+ * {boolean} isFile always true (readonly)
+ * {boolean} isDirectory always false (readonly)
+ * {DOMString} name of the file, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the file (readonly)
+ * {FileSystem} filesystem on which the file resides (readonly)
+ */
+var FileEntry = function(name, fullPath) {
+ FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]);
+};
+
+utils.extend(FileEntry, Entry);
+
+/**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new FileWriter
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
+ this.file(function(filePointer) {
+ var writer = new FileWriter(filePointer);
+
+ if (writer.fileName === null || writer.fileName === "") {
+ errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR));
+ } else {
+ successCallback && successCallback(writer);
+ }
+ }, errorCallback);
+};
+
+/**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new File object
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.file = function(successCallback, errorCallback) {
+ var win = successCallback && function(f) {
+ var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size);
+ successCallback(file);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getFileMetadata", [this.fullPath]);
+};
+
+
+module.exports = FileEntry;
+
+});
+
+// file: lib/common/plugin/FileError.js
+define("cordova/plugin/FileError", function(require, exports, module) {
+
+/**
+ * FileError
+ */
+function FileError(error) {
+ this.code = error || null;
+}
+
+// File error codes
+// Found in DOMException
+FileError.NOT_FOUND_ERR = 1;
+FileError.SECURITY_ERR = 2;
+FileError.ABORT_ERR = 3;
+
+// Added by File API specification
+FileError.NOT_READABLE_ERR = 4;
+FileError.ENCODING_ERR = 5;
+FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
+FileError.INVALID_STATE_ERR = 7;
+FileError.SYNTAX_ERR = 8;
+FileError.INVALID_MODIFICATION_ERR = 9;
+FileError.QUOTA_EXCEEDED_ERR = 10;
+FileError.TYPE_MISMATCH_ERR = 11;
+FileError.PATH_EXISTS_ERR = 12;
+
+module.exports = FileError;
+
+});
+
+// file: lib/common/plugin/FileReader.js
+define("cordova/plugin/FileReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ modulemapper = require('cordova/modulemapper'),
+ utils = require('cordova/utils'),
+ File = require('cordova/plugin/File'),
+ FileError = require('cordova/plugin/FileError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent'),
+ origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader');
+
+/**
+ * This class reads the mobile device file system.
+ *
+ * For Android:
+ * The root directory is the root of the file system.
+ * To read from the SD card, the file name is "sdcard/my_file.txt"
+ * @constructor
+ */
+var FileReader = function() {
+ this._readyState = 0;
+ this._error = null;
+ this._result = null;
+ this._fileName = '';
+ this._realReader = origFileReader ? new origFileReader() : {};
+};
+
+// States
+FileReader.EMPTY = 0;
+FileReader.LOADING = 1;
+FileReader.DONE = 2;
+
+utils.defineGetter(FileReader.prototype, 'readyState', function() {
+ return this._fileName ? this._readyState : this._realReader.readyState;
+});
+
+utils.defineGetter(FileReader.prototype, 'error', function() {
+ return this._fileName ? this._error: this._realReader.error;
+});
+
+utils.defineGetter(FileReader.prototype, 'result', function() {
+ return this._fileName ? this._result: this._realReader.result;
+});
+
+function defineEvent(eventName) {
+ utils.defineGetterSetter(FileReader.prototype, eventName, function() {
+ return this._realReader[eventName] || null;
+ }, function(value) {
+ this._realReader[eventName] = value;
+ });
+}
+defineEvent('onloadstart'); // When the read starts.
+defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
+defineEvent('onload'); // When the read has successfully completed.
+defineEvent('onerror'); // When the read has failed (see errors).
+defineEvent('onloadend'); // When the request has completed (either in success or failure).
+defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method.
+
+function initRead(reader, file) {
+ // Already loading something
+ if (reader.readyState == FileReader.LOADING) {
+ throw new FileError(FileError.INVALID_STATE_ERR);
+ }
+
+ reader._result = null;
+ reader._error = null;
+ reader._readyState = FileReader.LOADING;
+
+ if (typeof file == 'string') {
+ // Deprecated in Cordova 2.4.
+ console.warning('Using a string argument with FileReader.readAs functions is deprecated.');
+ reader._fileName = file;
+ } else if (typeof file.fullPath == 'string') {
+ reader._fileName = file.fullPath;
+ } else {
+ reader._fileName = '';
+ return true;
+ }
+
+ reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
+}
+
+/**
+ * Abort reading file.
+ */
+FileReader.prototype.abort = function() {
+ if (origFileReader && !this._fileName) {
+ return this._realReader.abort();
+ }
+ this._result = null;
+
+ if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) {
+ return;
+ }
+
+ this._readyState = FileReader.DONE;
+
+ // If abort callback
+ if (typeof this.onabort === 'function') {
+ this.onabort(new ProgressEvent('abort', {target:this}));
+ }
+ // If load end callback
+ if (typeof this.onloadend === 'function') {
+ this.onloadend(new ProgressEvent('loadend', {target:this}));
+ }
+};
+
+/**
+ * Read text file.
+ *
+ * @param file {File} File object containing file properties
+ * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets)
+ */
+FileReader.prototype.readAsText = function(file, encoding) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsText(file, encoding);
+ }
+
+ // Default encoding is UTF-8
+ var enc = encoding ? encoding : "UTF-8";
+ var me = this;
+ var execArgs = [this._fileName, enc];
+
+ // Maybe add slice parameters.
+ if (file.end < file.size) {
+ execArgs.push(file.start, file.end);
+ } else if (file.start > 0) {
+ execArgs.push(file.start);
+ }
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // Save result
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // null result
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsText", execArgs);
+};
+
+
+/**
+ * Read file and return data as a base64 encoded data url.
+ * A data url is of the form:
+ * data:[<mediatype>][;base64],<data>
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsDataURL(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName];
+
+ // Maybe add slice parameters.
+ if (file.end < file.size) {
+ execArgs.push(file.start, file.end);
+ } else if (file.start > 0) {
+ execArgs.push(file.start);
+ }
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // Save result
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsDataURL", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsBinaryString = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsBinaryString(file);
+ }
+ // TODO - Can't return binary data to browser.
+ console.log('method "readAsBinaryString" is not supported at this time.');
+ this.abort();
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsArrayBuffer = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsArrayBuffer(file);
+ }
+ // TODO - Can't return binary data to browser.
+ console.log('This method is not supported at this time.');
+ this.abort();
+};
+
+module.exports = FileReader;
+
+});
+
+// file: lib/common/plugin/FileSystem.js
+define("cordova/plugin/FileSystem", function(require, exports, module) {
+
+var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+
+/**
+ * An interface representing a file system
+ *
+ * @constructor
+ * {DOMString} name the unique name of the file system (readonly)
+ * {DirectoryEntry} root directory of the file system (readonly)
+ */
+var FileSystem = function(name, root) {
+ this.name = name || null;
+ if (root) {
+ this.root = new DirectoryEntry(root.name, root.fullPath);
+ }
+};
+
+module.exports = FileSystem;
+
+});
+
+// file: lib/common/plugin/FileTransfer.js
+define("cordova/plugin/FileTransfer", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ FileTransferError = require('cordova/plugin/FileTransferError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+function newProgressEvent(result) {
+ var pe = new ProgressEvent();
+ pe.lengthComputable = result.lengthComputable;
+ pe.loaded = result.loaded;
+ pe.total = result.total;
+ return pe;
+}
+
+var idCounter = 0;
+
+/**
+ * FileTransfer uploads a file to a remote server.
+ * @constructor
+ */
+var FileTransfer = function() {
+ this._id = ++idCounter;
+ this.onprogress = null; // optional callback
+};
+
+/**
+* Given an absolute file path, uploads a file on the device to a remote server
+* using a multipart HTTP request.
+* @param filePath {String} Full path of the file on the device
+* @param server {String} URL of the server to receive the file
+* @param successCallback (Function} Callback to be invoked when upload has completed
+* @param errorCallback {Function} Callback to be invoked upon error
+* @param options {FileUploadOptions} Optional parameters such as file name and mimetype
+* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+*/
+FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) {
+ argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments);
+ // check for options
+ var fileKey = null;
+ var fileName = null;
+ var mimeType = null;
+ var params = null;
+ var chunkedMode = true;
+ var headers = null;
+ if (options) {
+ fileKey = options.fileKey;
+ fileName = options.fileName;
+ mimeType = options.mimeType;
+ headers = options.headers;
+ if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
+ chunkedMode = options.chunkedMode;
+ }
+ if (options.params) {
+ params = options.params;
+ }
+ else {
+ params = {};
+ }
+ }
+
+ var fail = errorCallback && function(e) {
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+ errorCallback(error);
+ };
+
+ var self = this;
+ var win = function(result) {
+ if (typeof result.lengthComputable != "undefined") {
+ if (self.onprogress) {
+ self.onprogress(newProgressEvent(result));
+ }
+ } else {
+ successCallback && successCallback(result);
+ }
+ };
+ exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id]);
+};
+
+/**
+ * Downloads a file form a given URL and saves it to the specified directory.
+ * @param source {String} URL of the server to receive the file
+ * @param target {String} Full path of the file on the device
+ * @param successCallback (Function} Callback to be invoked when upload has completed
+ * @param errorCallback {Function} Callback to be invoked upon error
+ * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ */
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) {
+ argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
+ var self = this;
+ var win = function(result) {
+ if (typeof result.lengthComputable != "undefined") {
+ if (self.onprogress) {
+ return self.onprogress(newProgressEvent(result));
+ }
+ } else if (successCallback) {
+ var entry = null;
+ if (result.isDirectory) {
+ entry = new (require('cordova/plugin/DirectoryEntry'))();
+ }
+ else if (result.isFile) {
+ entry = new (require('cordova/plugin/FileEntry'))();
+ }
+ entry.isDirectory = result.isDirectory;
+ entry.isFile = result.isFile;
+ entry.name = result.name;
+ entry.fullPath = result.fullPath;
+ successCallback(entry);
+ }
+ };
+
+ var fail = errorCallback && function(e) {
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+ errorCallback(error);
+ };
+
+ exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id]);
+};
+
+/**
+ * Aborts the ongoing file transfer on this object
+ * @param successCallback {Function} Callback to be invoked upon success
+ * @param errorCallback {Function} Callback to be invoked upon error
+ */
+FileTransfer.prototype.abort = function(successCallback, errorCallback) {
+ exec(successCallback, errorCallback, 'FileTransfer', 'abort', [this._id]);
+};
+
+module.exports = FileTransfer;
+
+});
+
+// file: lib/common/plugin/FileTransferError.js
+define("cordova/plugin/FileTransferError", function(require, exports, module) {
+
+/**
+ * FileTransferError
+ * @constructor
+ */
+var FileTransferError = function(code, source, target, status, body) {
+ this.code = code || null;
+ this.source = source || null;
+ this.target = target || null;
+ this.http_status = status || null;
+ this.body = body || null;
+};
+
+FileTransferError.FILE_NOT_FOUND_ERR = 1;
+FileTransferError.INVALID_URL_ERR = 2;
+FileTransferError.CONNECTION_ERR = 3;
+FileTransferError.ABORT_ERR = 4;
+
+module.exports = FileTransferError;
+
+});
+
+// file: lib/common/plugin/FileUploadOptions.js
+define("cordova/plugin/FileUploadOptions", function(require, exports, module) {
+
+/**
+ * Options to customize the HTTP request used to upload files.
+ * @constructor
+ * @param fileKey {String} Name of file request parameter.
+ * @param fileName {String} Filename to be used by the server. Defaults to image.jpg.
+ * @param mimeType {String} Mimetype of the uploaded file. Defaults to image/jpeg.
+ * @param params {Object} Object with key: value params to send to the server.
+ * @param headers {Object} Keys are header names, values are header values. Multiple
+ * headers of the same name are not supported.
+ */
+var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers) {
+ this.fileKey = fileKey || null;
+ this.fileName = fileName || null;
+ this.mimeType = mimeType || null;
+ this.params = params || null;
+ this.headers = headers || null;
+};
+
+module.exports = FileUploadOptions;
+
+});
+
+// file: lib/common/plugin/FileUploadResult.js
+define("cordova/plugin/FileUploadResult", function(require, exports, module) {
+
+/**
+ * FileUploadResult
+ * @constructor
+ */
+var FileUploadResult = function() {
+ this.bytesSent = 0;
+ this.responseCode = null;
+ this.response = null;
+};
+
+module.exports = FileUploadResult;
+
+});
+
+// file: lib/common/plugin/FileWriter.js
+define("cordova/plugin/FileWriter", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+/**
+ * This class writes to the mobile device file system.
+ *
+ * For Android:
+ * The root directory is the root of the file system.
+ * To write to the SD card, the file name is "sdcard/my_file.txt"
+ *
+ * @constructor
+ * @param file {File} File object containing file properties
+ * @param append if true write to the end of the file, otherwise overwrite the file
+ */
+var FileWriter = function(file) {
+ this.fileName = "";
+ this.length = 0;
+ if (file) {
+ this.fileName = file.fullPath || file;
+ this.length = file.size || 0;
+ }
+ // default is to write at the beginning of the file
+ this.position = 0;
+
+ this.readyState = 0; // EMPTY
+
+ this.result = null;
+
+ // Error
+ this.error = null;
+
+ // Event handlers
+ this.onwritestart = null; // When writing starts
+ this.onprogress = null; // While writing the file, and reporting partial file data
+ this.onwrite = null; // When the write has successfully completed.
+ this.onwriteend = null; // When the request has completed (either in success or failure).
+ this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method.
+ this.onerror = null; // When the write has failed (see errors).
+};
+
+// States
+FileWriter.INIT = 0;
+FileWriter.WRITING = 1;
+FileWriter.DONE = 2;
+
+/**
+ * Abort writing file.
+ */
+FileWriter.prototype.abort = function() {
+ // check for invalid state
+ if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
+ throw new FileError(FileError.INVALID_STATE_ERR);
+ }
+
+ // set error
+ this.error = new FileError(FileError.ABORT_ERR);
+
+ this.readyState = FileWriter.DONE;
+
+ // If abort callback
+ if (typeof this.onabort === "function") {
+ this.onabort(new ProgressEvent("abort", {"target":this}));
+ }
+
+ // If write end callback
+ if (typeof this.onwriteend === "function") {
+ this.onwriteend(new ProgressEvent("writeend", {"target":this}));
+ }
+};
+
+/**
+ * Writes data to the file
+ *
+ * @param text to be written
+ */
+FileWriter.prototype.write = function(text) {
+ // Throw an exception if we are already writing a file
+ if (this.readyState === FileWriter.WRITING) {
+ throw new FileError(FileError.INVALID_STATE_ERR);
+ }
+
+ // WRITING state
+ this.readyState = FileWriter.WRITING;
+
+ var me = this;
+
+ // If onwritestart callback
+ if (typeof me.onwritestart === "function") {
+ me.onwritestart(new ProgressEvent("writestart", {"target":me}));
+ }
+
+ // Write file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileWriter.DONE) {
+ return;
+ }
+
+ // position always increases by bytes written because file would be extended
+ me.position += r;
+ // The length of the file is now where we are done writing.
+
+ me.length = me.position;
+
+ // DONE state
+ me.readyState = FileWriter.DONE;
+
+ // If onwrite callback
+ if (typeof me.onwrite === "function") {
+ me.onwrite(new ProgressEvent("write", {"target":me}));
+ }
+
+ // If onwriteend callback
+ if (typeof me.onwriteend === "function") {
+ me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileWriter.DONE) {
+ return;
+ }
+
+ // DONE state
+ me.readyState = FileWriter.DONE;
+
+ // Save error
+ me.error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {"target":me}));
+ }
+
+ // If onwriteend callback
+ if (typeof me.onwriteend === "function") {
+ me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+ }
+ }, "File", "write", [this.fileName, text, this.position]);
+};
+
+/**
+ * Moves the file pointer to the location specified.
+ *
+ * If the offset is a negative number the position of the file
+ * pointer is rewound. If the offset is greater than the file
+ * size the position is set to the end of the file.
+ *
+ * @param offset is the location to move the file pointer to.
+ */
+FileWriter.prototype.seek = function(offset) {
+ // Throw an exception if we are already writing a file
+ if (this.readyState === FileWriter.WRITING) {
+ throw new FileError(FileError.INVALID_STATE_ERR);
+ }
+
+ if (!offset && offset !== 0) {
+ return;
+ }
+
+ // See back from end of file.
+ if (offset < 0) {
+ this.position = Math.max(offset + this.length, 0);
+ }
+ // Offset is bigger than file size so set position
+ // to the end of the file.
+ else if (offset > this.length) {
+ this.position = this.length;
+ }
+ // Offset is between 0 and file size so set the position
+ // to start writing.
+ else {
+ this.position = offset;
+ }
+};
+
+/**
+ * Truncates the file to the size specified.
+ *
+ * @param size to chop the file at.
+ */
+FileWriter.prototype.truncate = function(size) {
+ // Throw an exception if we are already writing a file
+ if (this.readyState === FileWriter.WRITING) {
+ throw new FileError(FileError.INVALID_STATE_ERR);
+ }
+
+ // WRITING state
+ this.readyState = FileWriter.WRITING;
+
+ var me = this;
+
+ // If onwritestart callback
+ if (typeof me.onwritestart === "function") {
+ me.onwritestart(new ProgressEvent("writestart", {"target":this}));
+ }
+
+ // Write file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileWriter.DONE) {
+ return;
+ }
+
+ // DONE state
+ me.readyState = FileWriter.DONE;
+
+ // Update the length of the file
+ me.length = r;
+ me.position = Math.min(me.position, r);
+
+ // If onwrite callback
+ if (typeof me.onwrite === "function") {
+ me.onwrite(new ProgressEvent("write", {"target":me}));
+ }
+
+ // If onwriteend callback
+ if (typeof me.onwriteend === "function") {
+ me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileWriter.DONE) {
+ return;
+ }
+
+ // DONE state
+ me.readyState = FileWriter.DONE;
+
+ // Save error
+ me.error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {"target":me}));
+ }
+
+ // If onwriteend callback
+ if (typeof me.onwriteend === "function") {
+ me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+ }
+ }, "File", "truncate", [this.fileName, size]);
+};
+
+module.exports = FileWriter;
+
+});
+
+// file: lib/common/plugin/Flags.js
+define("cordova/plugin/Flags", function(require, exports, module) {
+
+/**
+ * Supplies arguments to methods that lookup or create files and directories.
+ *
+ * @param create
+ * {boolean} file or directory if it doesn't exist
+ * @param exclusive
+ * {boolean} used with create; if true the command will fail if
+ * target path exists
+ */
+function Flags(create, exclusive) {
+ this.create = create || false;
+ this.exclusive = exclusive || false;
+}
+
+module.exports = Flags;
+
+});
+
+// file: lib/common/plugin/GlobalizationError.js
+define("cordova/plugin/GlobalizationError", function(require, exports, module) {
+
+
+/**
+ * Globalization error object
+ *
+ * @constructor
+ * @param code
+ * @param message
+ */
+var GlobalizationError = function(code, message) {
+ this.code = code || null;
+ this.message = message || '';
+};
+
+// Globalization error codes
+GlobalizationError.UNKNOWN_ERROR = 0;
+GlobalizationError.FORMATTING_ERROR = 1;
+GlobalizationError.PARSING_ERROR = 2;
+GlobalizationError.PATTERN_ERROR = 3;
+
+module.exports = GlobalizationError;
+
+});
+
+// file: lib/common/plugin/InAppBrowser.js
+define("cordova/plugin/InAppBrowser", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var channel = require('cordova/channel');
+
+function InAppBrowser() {
+ this.channels = {
+ 'loadstart': channel.create('loadstart'),
+ 'loadstop' : channel.create('loadstop'),
+ 'exit' : channel.create('exit')
+ };
+}
+
+InAppBrowser.prototype = {
+ _eventHandler: function (event) {
+ if (event.type in this.channels) {
+ this.channels[event.type].fire(event);
+ }
+ },
+ close: function (eventname) {
+ exec(null, null, "InAppBrowser", "close", []);
+ },
+ addEventListener: function (eventname,f) {
+ if (eventname in this.channels) {
+ this.channels[eventname].subscribe(f);
+ }
+ },
+ removeEventListener: function(eventname, f) {
+ if (eventname in this.channels) {
+ this.channels[eventname].unsubscribe(f);
+ }
+ }
+};
+
+module.exports = function(strUrl, strWindowName, strWindowFeatures) {
+ var iab = new InAppBrowser();
+ var cb = function(eventname) {
+ iab._eventHandler(eventname);
+ };
+ exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
+ return iab;
+};
+
+
+});
+
+// file: lib/common/plugin/LocalFileSystem.js
+define("cordova/plugin/LocalFileSystem", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * Represents a local file system.
+ */
+var LocalFileSystem = function() {
+
+};
+
+LocalFileSystem.TEMPORARY = 0; //temporary, with no guarantee of persistence
+LocalFileSystem.PERSISTENT = 1; //persistent
+
+module.exports = LocalFileSystem;
+
+});
+
+// file: lib/common/plugin/Media.js
+define("cordova/plugin/Media", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ utils = require('cordova/utils'),
+ exec = require('cordova/exec');
+
+var mediaObjects = {};
+
+/**
+ * This class provides access to the device media, interfaces to both sound and video
+ *
+ * @constructor
+ * @param src The file name or url to play
+ * @param successCallback The callback to be called when the file is done playing or recording.
+ * successCallback()
+ * @param errorCallback The callback to be called if there is an error.
+ * errorCallback(int errorCode) - OPTIONAL
+ * @param statusCallback The callback to be called when media status has changed.
+ * statusCallback(int statusCode) - OPTIONAL
+ */
+var Media = function(src, successCallback, errorCallback, statusCallback) {
+ argscheck.checkArgs('SFFF', 'Media', arguments);
+ this.id = utils.createUUID();
+ mediaObjects[this.id] = this;
+ this.src = src;
+ this.successCallback = successCallback;
+ this.errorCallback = errorCallback;
+ this.statusCallback = statusCallback;
+ this._duration = -1;
+ this._position = -1;
+ exec(null, this.errorCallback, "Media", "create", [this.id, this.src]);
+};
+
+// Media messages
+Media.MEDIA_STATE = 1;
+Media.MEDIA_DURATION = 2;
+Media.MEDIA_POSITION = 3;
+Media.MEDIA_ERROR = 9;
+
+// Media states
+Media.MEDIA_NONE = 0;
+Media.MEDIA_STARTING = 1;
+Media.MEDIA_RUNNING = 2;
+Media.MEDIA_PAUSED = 3;
+Media.MEDIA_STOPPED = 4;
+Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"];
+
+// "static" function to return existing objs.
+Media.get = function(id) {
+ return mediaObjects[id];
+};
+
+/**
+ * Start or resume playing audio file.
+ */
+Media.prototype.play = function(options) {
+ exec(null, null, "Media", "startPlayingAudio", [this.id, this.src, options]);
+};
+
+/**
+ * Stop playing audio file.
+ */
+Media.prototype.stop = function() {
+ var me = this;
+ exec(function() {
+ me._position = 0;
+ }, this.errorCallback, "Media", "stopPlayingAudio", [this.id]);
+};
+
+/**
+ * Seek or jump to a new time in the track..
+ */
+Media.prototype.seekTo = function(milliseconds) {
+ var me = this;
+ exec(function(p) {
+ me._position = p;
+ }, this.errorCallback, "Media", "seekToAudio", [this.id, milliseconds]);
+};
+
+/**
+ * Pause playing audio file.
+ */
+Media.prototype.pause = function() {
+ exec(null, this.errorCallback, "Media", "pausePlayingAudio", [this.id]);
+};
+
+/**
+ * Get duration of an audio file.
+ * The duration is only set for audio that is playing, paused or stopped.
+ *
+ * @return duration or -1 if not known.
+ */
+Media.prototype.getDuration = function() {
+ return this._duration;
+};
+
+/**
+ * Get position of audio.
+ */
+Media.prototype.getCurrentPosition = function(success, fail) {
+ var me = this;
+ exec(function(p) {
+ me._position = p;
+ success(p);
+ }, fail, "Media", "getCurrentPositionAudio", [this.id]);
+};
+
+/**
+ * Start recording audio file.
+ */
+Media.prototype.startRecord = function() {
+ exec(null, this.errorCallback, "Media", "startRecordingAudio", [this.id, this.src]);
+};
+
+/**
+ * Stop recording audio file.
+ */
+Media.prototype.stopRecord = function() {
+ exec(null, this.errorCallback, "Media", "stopRecordingAudio", [this.id]);
+};
+
+/**
+ * Release the resources.
+ */
+Media.prototype.release = function() {
+ exec(null, this.errorCallback, "Media", "release", [this.id]);
+};
+
+/**
+ * Adjust the volume.
+ */
+Media.prototype.setVolume = function(volume) {
+ exec(null, null, "Media", "setVolume", [this.id, volume]);
+};
+
+/**
+ * Audio has status update.
+ * PRIVATE
+ *
+ * @param id The media object id (string)
+ * @param msgType The 'type' of update this is
+ * @param value Use of value is determined by the msgType
+ */
+Media.onStatus = function(id, msgType, value) {
+
+ var media = mediaObjects[id];
+
+ if(media) {
+ switch(msgType) {
+ case Media.MEDIA_STATE :
+ media.statusCallback && media.statusCallback(value);
+ if(value == Media.MEDIA_STOPPED) {
+ media.successCallback && media.successCallback();
+ }
+ break;
+ case Media.MEDIA_DURATION :
+ media._duration = value;
+ break;
+ case Media.MEDIA_ERROR :
+ media.errorCallback && media.errorCallback(value);
+ break;
+ case Media.MEDIA_POSITION :
+ media._position = Number(value);
+ break;
+ default :
+ console.error && console.error("Unhandled Media.onStatus :: " + msgType);
+ break;
+ }
+ }
+ else {
+ console.error && console.error("Received Media.onStatus callback for unknown media :: " + id);
+ }
+
+};
+
+module.exports = Media;
+
+});
+
+// file: lib/common/plugin/MediaError.js
+define("cordova/plugin/MediaError", function(require, exports, module) {
+
+/**
+ * This class contains information about any Media errors.
+*/
+/*
+ According to :: http://dev.w3.org/html5/spec-author-view/video.html#mediaerror
+ We should never be creating these objects, we should just implement the interface
+ which has 1 property for an instance, 'code'
+
+ instead of doing :
+ errorCallbackFunction( new MediaError(3,'msg') );
+we should simply use a literal :
+ errorCallbackFunction( {'code':3} );
+ */
+
+ var _MediaError = window.MediaError;
+
+
+if(!_MediaError) {
+ window.MediaError = _MediaError = function(code, msg) {
+ this.code = (typeof code != 'undefined') ? code : null;
+ this.message = msg || ""; // message is NON-standard! do not use!
+ };
+}
+
+_MediaError.MEDIA_ERR_NONE_ACTIVE = _MediaError.MEDIA_ERR_NONE_ACTIVE || 0;
+_MediaError.MEDIA_ERR_ABORTED = _MediaError.MEDIA_ERR_ABORTED || 1;
+_MediaError.MEDIA_ERR_NETWORK = _MediaError.MEDIA_ERR_NETWORK || 2;
+_MediaError.MEDIA_ERR_DECODE = _MediaError.MEDIA_ERR_DECODE || 3;
+_MediaError.MEDIA_ERR_NONE_SUPPORTED = _MediaError.MEDIA_ERR_NONE_SUPPORTED || 4;
+// TODO: MediaError.MEDIA_ERR_NONE_SUPPORTED is legacy, the W3 spec now defines it as below.
+// as defined by http://dev.w3.org/html5/spec-author-view/video.html#error-codes
+_MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = _MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED || 4;
+
+module.exports = _MediaError;
+
+});
+
+// file: lib/common/plugin/MediaFile.js
+define("cordova/plugin/MediaFile", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ File = require('cordova/plugin/File'),
+ CaptureError = require('cordova/plugin/CaptureError');
+/**
+ * Represents a single file.
+ *
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+var MediaFile = function(name, fullPath, type, lastModifiedDate, size){
+ MediaFile.__super__.constructor.apply(this, arguments);
+};
+
+utils.extend(MediaFile, File);
+
+/**
+ * Request capture format data for a specific file and type
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ */
+MediaFile.prototype.getFormatData = function(successCallback, errorCallback) {
+ if (typeof this.fullPath === "undefined" || this.fullPath === null) {
+ errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT));
+ } else {
+ exec(successCallback, errorCallback, "Capture", "getFormatData", [this.fullPath, this.type]);
+ }
+};
+
+module.exports = MediaFile;
+
+});
+
+// file: lib/common/plugin/MediaFileData.js
+define("cordova/plugin/MediaFileData", function(require, exports, module) {
+
+/**
+ * MediaFileData encapsulates format information of a media file.
+ *
+ * @param {DOMString} codecs
+ * @param {long} bitrate
+ * @param {long} height
+ * @param {long} width
+ * @param {float} duration
+ */
+var MediaFileData = function(codecs, bitrate, height, width, duration){
+ this.codecs = codecs || null;
+ this.bitrate = bitrate || 0;
+ this.height = height || 0;
+ this.width = width || 0;
+ this.duration = duration || 0;
+};
+
+module.exports = MediaFileData;
+
+});
+
+// file: lib/common/plugin/Metadata.js
+define("cordova/plugin/Metadata", function(require, exports, module) {
+
+/**
+ * Information about the state of the file or directory
+ *
+ * {Date} modificationTime (readonly)
+ */
+var Metadata = function(time) {
+ this.modificationTime = (typeof time != 'undefined'?new Date(time):null);
+};
+
+module.exports = Metadata;
+
+});
+
+// file: lib/common/plugin/Position.js
+define("cordova/plugin/Position", function(require, exports, module) {
+
+var Coordinates = require('cordova/plugin/Coordinates');
+
+var Position = function(coords, timestamp) {
+ if (coords) {
+ this.coords = new Coordinates(coords.latitude, coords.longitude, coords.altitude, coords.accuracy, coords.heading, coords.velocity, coords.altitudeAccuracy);
+ } else {
+ this.coords = new Coordinates();
+ }
+ this.timestamp = (timestamp !== undefined) ? timestamp : new Date();
+};
+
+module.exports = Position;
+
+});
+
+// file: lib/common/plugin/PositionError.js
+define("cordova/plugin/PositionError", function(require, exports, module) {
+
+/**
+ * Position error object
+ *
+ * @constructor
+ * @param code
+ * @param message
+ */
+var PositionError = function(code, message) {
+ this.code = code || null;
+ this.message = message || '';
+};
+
+PositionError.PERMISSION_DENIED = 1;
+PositionError.POSITION_UNAVAILABLE = 2;
+PositionError.TIMEOUT = 3;
+
+module.exports = PositionError;
+
+});
+
+// file: lib/common/plugin/ProgressEvent.js
+define("cordova/plugin/ProgressEvent", function(require, exports, module) {
+
+// If ProgressEvent exists in global context, use it already, otherwise use our own polyfill
+// Feature test: See if we can instantiate a native ProgressEvent;
+// if so, use that approach,
+// otherwise fill-in with our own implementation.
+//
+// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview.
+var ProgressEvent = (function() {
+ /*
+ var createEvent = function(data) {
+ var event = document.createEvent('Events');
+ event.initEvent('ProgressEvent', false, false);
+ if (data) {
+ for (var i in data) {
+ if (data.hasOwnProperty(i)) {
+ event[i] = data[i];
+ }
+ }
+ if (data.target) {
+ // TODO: cannot call <some_custom_object>.dispatchEvent
+ // need to first figure out how to implement EventTarget
+ }
+ }
+ return event;
+ };
+ try {
+ var ev = createEvent({type:"abort",target:document});
+ return function ProgressEvent(type, data) {
+ data.type = type;
+ return createEvent(data);
+ };
+ } catch(e){
+ */
+ return function ProgressEvent(type, dict) {
+ this.type = type;
+ this.bubbles = false;
+ this.cancelBubble = false;
+ this.cancelable = false;
+ this.lengthComputable = false;
+ this.loaded = dict && dict.loaded ? dict.loaded : 0;
+ this.total = dict && dict.total ? dict.total : 0;
+ this.target = dict && dict.target ? dict.target : null;
+ };
+ //}
+})();
+
+module.exports = ProgressEvent;
+
+});
+
+// file: lib/common/plugin/accelerometer.js
+define("cordova/plugin/accelerometer", function(require, exports, module) {
+
+/**
+ * This class provides access to device accelerometer data.
+ * @constructor
+ */
+var argscheck = require('cordova/argscheck'),
+ utils = require("cordova/utils"),
+ exec = require("cordova/exec"),
+ Acceleration = require('cordova/plugin/Acceleration');
+
+// Is the accel sensor running?
+var running = false;
+
+// Keeps reference to watchAcceleration calls.
+var timers = {};
+
+// Array of listeners; used to keep track of when we should call start and stop.
+var listeners = [];
+
+// Last returned acceleration object from native
+var accel = null;
+
+// Tells native to start.
+function start() {
+ exec(function(a) {
+ var tempListeners = listeners.slice(0);
+ accel = new Acceleration(a.x, a.y, a.z, a.timestamp);
+ for (var i = 0, l = tempListeners.length; i < l; i++) {
+ tempListeners[i].win(accel);
+ }
+ }, function(e) {
+ var tempListeners = listeners.slice(0);
+ for (var i = 0, l = tempListeners.length; i < l; i++) {
+ tempListeners[i].fail(e);
+ }
+ }, "Accelerometer", "start", []);
+ running = true;
+}
+
+// Tells native to stop.
+function stop() {
+ exec(null, null, "Accelerometer", "stop", []);
+ running = false;
+}
+
+// Adds a callback pair to the listeners array
+function createCallbackPair(win, fail) {
+ return {win:win, fail:fail};
+}
+
+// Removes a win/fail listener pair from the listeners array
+function removeListeners(l) {
+ var idx = listeners.indexOf(l);
+ if (idx > -1) {
+ listeners.splice(idx, 1);
+ if (listeners.length === 0) {
+ stop();
+ }
+ }
+}
+
+var accelerometer = {
+ /**
+ * Asynchronously acquires the current acceleration.
+ *
+ * @param {Function} successCallback The function to call when the acceleration data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the acceleration data. (OPTIONAL)
+ * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL)
+ */
+ getCurrentAcceleration: function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'accelerometer.getCurrentAcceleration', arguments);
+
+ var p;
+ var win = function(a) {
+ removeListeners(p);
+ successCallback(a);
+ };
+ var fail = function(e) {
+ removeListeners(p);
+ errorCallback && errorCallback(e);
+ };
+
+ p = createCallbackPair(win, fail);
+ listeners.push(p);
+
+ if (!running) {
+ start();
+ }
+ },
+
+ /**
+ * Asynchronously acquires the acceleration repeatedly at a given interval.
+ *
+ * @param {Function} successCallback The function to call each time the acceleration data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the acceleration data. (OPTIONAL)
+ * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL)
+ * @return String The watch id that must be passed to #clearWatch to stop watching.
+ */
+ watchAcceleration: function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'accelerometer.watchAcceleration', arguments);
+ // Default interval (10 sec)
+ var frequency = (options && options.frequency && typeof options.frequency == 'number') ? options.frequency : 10000;
+
+ // Keep reference to watch id, and report accel readings as often as defined in frequency
+ var id = utils.createUUID();
+
+ var p = createCallbackPair(function(){}, function(e) {
+ removeListeners(p);
+ errorCallback && errorCallback(e);
+ });
+ listeners.push(p);
+
+ timers[id] = {
+ timer:window.setInterval(function() {
+ if (accel) {
+ successCallback(accel);
+ }
+ }, frequency),
+ listeners:p
+ };
+
+ if (running) {
+ // If we're already running then immediately invoke the success callback
+ // but only if we have retrieved a value, sample code does not check for null ...
+ if (accel) {
+ successCallback(accel);
+ }
+ } else {
+ start();
+ }
+
+ return id;
+ },
+
+ /**
+ * Clears the specified accelerometer watch.
+ *
+ * @param {String} id The id of the watch returned from #watchAcceleration.
+ */
+ clearWatch: function(id) {
+ // Stop javascript timer & remove from timer list
+ if (id && timers[id]) {
+ window.clearInterval(timers[id].timer);
+ removeListeners(timers[id].listeners);
+ delete timers[id];
+ }
+ }
+};
+
+module.exports = accelerometer;
+
+});
+
+// file: lib/common/plugin/accelerometer/symbols.js
+define("cordova/plugin/accelerometer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Acceleration', 'Acceleration');
+modulemapper.defaults('cordova/plugin/accelerometer', 'navigator.accelerometer');
+
+});
+
+// file: lib/common/plugin/battery.js
+define("cordova/plugin/battery", function(require, exports, module) {
+
+/**
+ * This class contains information about the current battery status.
+ * @constructor
+ */
+var cordova = require('cordova'),
+ exec = require('cordova/exec');
+
+function handlers() {
+ return battery.channels.batterystatus.numHandlers +
+ battery.channels.batterylow.numHandlers +
+ battery.channels.batterycritical.numHandlers;
+}
+
+var Battery = function() {
+ this._level = null;
+ this._isPlugged = null;
+ // Create new event handlers on the window (returns a channel instance)
+ this.channels = {
+ batterystatus:cordova.addWindowEventHandler("batterystatus"),
+ batterylow:cordova.addWindowEventHandler("batterylow"),
+ batterycritical:cordova.addWindowEventHandler("batterycritical")
+ };
+ for (var key in this.channels) {
+ this.channels[key].onHasSubscribersChange = Battery.onHasSubscribersChange;
+ }
+};
+/**
+ * Event handlers for when callbacks get registered for the battery.
+ * Keep track of how many handlers we have so we can start and stop the native battery listener
+ * appropriately (and hopefully save on battery life!).
+ */
+Battery.onHasSubscribersChange = function() {
+ // If we just registered the first handler, make sure native listener is started.
+ if (this.numHandlers === 1 && handlers() === 1) {
+ exec(battery._status, battery._error, "Battery", "start", []);
+ } else if (handlers() === 0) {
+ exec(null, null, "Battery", "stop", []);
+ }
+};
+
+/**
+ * Callback for battery status
+ *
+ * @param {Object} info keys: level, isPlugged
+ */
+Battery.prototype._status = function(info) {
+ if (info) {
+ var me = battery;
+ var level = info.level;
+ if (me._level !== level || me._isPlugged !== info.isPlugged) {
+ // Fire batterystatus event
+ cordova.fireWindowEvent("batterystatus", info);
+
+ // Fire low battery event
+ if (level === 20 || level === 5) {
+ if (level === 20) {
+ cordova.fireWindowEvent("batterylow", info);
+ }
+ else {
+ cordova.fireWindowEvent("batterycritical", info);
+ }
+ }
+ }
+ me._level = level;
+ me._isPlugged = info.isPlugged;
+ }
+};
+
+/**
+ * Error callback for battery start
+ */
+Battery.prototype._error = function(e) {
+ console.log("Error initializing Battery: " + e);
+};
+
+var battery = new Battery();
+
+module.exports = battery;
+
+});
+
+// file: lib/common/plugin/battery/symbols.js
+define("cordova/plugin/battery/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/battery', 'navigator.battery');
+
+});
+
+// file: lib/common/plugin/camera/symbols.js
+define("cordova/plugin/camera/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Camera', 'navigator.camera');
+modulemapper.defaults('cordova/plugin/CameraConstants', 'Camera');
+modulemapper.defaults('cordova/plugin/CameraPopoverOptions', 'CameraPopoverOptions');
+
+});
+
+// file: lib/common/plugin/capture.js
+define("cordova/plugin/capture", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ MediaFile = require('cordova/plugin/MediaFile');
+
+/**
+ * Launches a capture of different types.
+ *
+ * @param (DOMString} type
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureVideoOptions} options
+ */
+function _capture(type, successCallback, errorCallback, options) {
+ var win = function(pluginResult) {
+ var mediaFiles = [];
+ var i;
+ for (i = 0; i < pluginResult.length; i++) {
+ var mediaFile = new MediaFile();
+ mediaFile.name = pluginResult[i].name;
+ mediaFile.fullPath = pluginResult[i].fullPath;
+ mediaFile.type = pluginResult[i].type;
+ mediaFile.lastModifiedDate = pluginResult[i].lastModifiedDate;
+ mediaFile.size = pluginResult[i].size;
+ mediaFiles.push(mediaFile);
+ }
+ successCallback(mediaFiles);
+ };
+ exec(win, errorCallback, "Capture", type, [options]);
+}
+/**
+ * The Capture interface exposes an interface to the camera and microphone of the hosting device.
+ */
+function Capture() {
+ this.supportedAudioModes = [];
+ this.supportedImageModes = [];
+ this.supportedVideoModes = [];
+}
+
+/**
+ * Launch audio recorder application for recording audio clip(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureAudioOptions} options
+ */
+Capture.prototype.captureAudio = function(successCallback, errorCallback, options){
+ _capture("captureAudio", successCallback, errorCallback, options);
+};
+
+/**
+ * Launch camera application for taking image(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureImageOptions} options
+ */
+Capture.prototype.captureImage = function(successCallback, errorCallback, options){
+ _capture("captureImage", successCallback, errorCallback, options);
+};
+
+/**
+ * Launch device camera application for recording video(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureVideoOptions} options
+ */
+Capture.prototype.captureVideo = function(successCallback, errorCallback, options){
+ _capture("captureVideo", successCallback, errorCallback, options);
+};
+
+
+module.exports = new Capture();
+
+});
+
+// file: lib/common/plugin/capture/symbols.js
+define("cordova/plugin/capture/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CaptureError', 'CaptureError');
+modulemapper.clobbers('cordova/plugin/CaptureAudioOptions', 'CaptureAudioOptions');
+modulemapper.clobbers('cordova/plugin/CaptureImageOptions', 'CaptureImageOptions');
+modulemapper.clobbers('cordova/plugin/CaptureVideoOptions', 'CaptureVideoOptions');
+modulemapper.clobbers('cordova/plugin/ConfigurationData', 'ConfigurationData');
+modulemapper.clobbers('cordova/plugin/MediaFile', 'MediaFile');
+modulemapper.clobbers('cordova/plugin/MediaFileData', 'MediaFileData');
+modulemapper.clobbers('cordova/plugin/capture', 'navigator.device.capture');
+
+});
+
+// file: lib/common/plugin/compass.js
+define("cordova/plugin/compass", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ utils = require('cordova/utils'),
+ CompassHeading = require('cordova/plugin/CompassHeading'),
+ CompassError = require('cordova/plugin/CompassError'),
+ timers = {},
+ compass = {
+ /**
+ * Asynchronously acquires the current heading.
+ * @param {Function} successCallback The function to call when the heading
+ * data is available
+ * @param {Function} errorCallback The function to call when there is an error
+ * getting the heading data.
+ * @param {CompassOptions} options The options for getting the heading data (not used).
+ */
+ getCurrentHeading:function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'compass.getCurrentHeading', arguments);
+
+ var win = function(result) {
+ var ch = new CompassHeading(result.magneticHeading, result.trueHeading, result.headingAccuracy, result.timestamp);
+ successCallback(ch);
+ };
+ var fail = errorCallback && function(code) {
+ var ce = new CompassError(code);
+ errorCallback(ce);
+ };
+
+ // Get heading
+ exec(win, fail, "Compass", "getHeading", [options]);
+ },
+
+ /**
+ * Asynchronously acquires the heading repeatedly at a given interval.
+ * @param {Function} successCallback The function to call each time the heading
+ * data is available
+ * @param {Function} errorCallback The function to call when there is an error
+ * getting the heading data.
+ * @param {HeadingOptions} options The options for getting the heading data
+ * such as timeout and the frequency of the watch. For iOS, filter parameter
+ * specifies to watch via a distance filter rather than time.
+ */
+ watchHeading:function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'compass.watchHeading', arguments);
+ // Default interval (100 msec)
+ var frequency = (options !== undefined && options.frequency !== undefined) ? options.frequency : 100;
+ var filter = (options !== undefined && options.filter !== undefined) ? options.filter : 0;
+
+ var id = utils.createUUID();
+ if (filter > 0) {
+ // is an iOS request for watch by filter, no timer needed
+ timers[id] = "iOS";
+ compass.getCurrentHeading(successCallback, errorCallback, options);
+ } else {
+ // Start watch timer to get headings
+ timers[id] = window.setInterval(function() {
+ compass.getCurrentHeading(successCallback, errorCallback);
+ }, frequency);
+ }
+
+ return id;
+ },
+
+ /**
+ * Clears the specified heading watch.
+ * @param {String} watchId The ID of the watch returned from #watchHeading.
+ */
+ clearWatch:function(id) {
+ // Stop javascript timer & remove from timer list
+ if (id && timers[id]) {
+ if (timers[id] != "iOS") {
+ clearInterval(timers[id]);
+ } else {
+ // is iOS watch by filter so call into device to stop
+ exec(null, null, "Compass", "stopHeading", []);
+ }
+ delete timers[id];
+ }
+ }
+ };
+
+module.exports = compass;
+
+});
+
+// file: lib/common/plugin/compass/symbols.js
+define("cordova/plugin/compass/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CompassHeading', 'CompassHeading');
+modulemapper.clobbers('cordova/plugin/CompassError', 'CompassError');
+modulemapper.clobbers('cordova/plugin/compass', 'navigator.compass');
+
+});
+
+// file: lib/common/plugin/console-via-logger.js
+define("cordova/plugin/console-via-logger", function(require, exports, module) {
+
+//------------------------------------------------------------------------------
+
+var logger = require("cordova/plugin/logger");
+var utils = require("cordova/utils");
+
+//------------------------------------------------------------------------------
+// object that we're exporting
+//------------------------------------------------------------------------------
+var console = module.exports;
+
+//------------------------------------------------------------------------------
+// copy of the original console object
+//------------------------------------------------------------------------------
+var WinConsole = window.console;
+
+//------------------------------------------------------------------------------
+// whether to use the logger
+//------------------------------------------------------------------------------
+var UseLogger = false;
+
+//------------------------------------------------------------------------------
+// Timers
+//------------------------------------------------------------------------------
+var Timers = {};
+
+//------------------------------------------------------------------------------
+// used for unimplemented methods
+//------------------------------------------------------------------------------
+function noop() {}
+
+//------------------------------------------------------------------------------
+// used for unimplemented methods
+//------------------------------------------------------------------------------
+console.useLogger = function (value) {
+ if (arguments.length) UseLogger = !!value;
+
+ if (UseLogger) {
+ if (logger.useConsole()) {
+ throw new Error("console and logger are too intertwingly");
+ }
+ }
+
+ return UseLogger;
+};
+
+//------------------------------------------------------------------------------
+console.log = function() {
+ if (logger.useConsole()) return;
+ logger.log.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.error = function() {
+ if (logger.useConsole()) return;
+ logger.error.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.warn = function() {
+ if (logger.useConsole()) return;
+ logger.warn.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.info = function() {
+ if (logger.useConsole()) return;
+ logger.info.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.debug = function() {
+ if (logger.useConsole()) return;
+ logger.debug.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.assert = function(expression) {
+ if (expression) return;
+
+ var message = utils.vformat(arguments[1], [].slice.call(arguments, 2));
+ console.log("ASSERT: " + message);
+};
+
+//------------------------------------------------------------------------------
+console.clear = function() {};
+
+//------------------------------------------------------------------------------
+console.dir = function(object) {
+ console.log("%o", object);
+};
+
+//------------------------------------------------------------------------------
+console.dirxml = function(node) {
+ console.log(node.innerHTML);
+};
+
+//------------------------------------------------------------------------------
+console.trace = noop;
+
+//------------------------------------------------------------------------------
+console.group = console.log;
+
+//------------------------------------------------------------------------------
+console.groupCollapsed = console.log;
+
+//------------------------------------------------------------------------------
+console.groupEnd = noop;
+
+//------------------------------------------------------------------------------
+console.time = function(name) {
+ Timers[name] = new Date().valueOf();
+};
+
+//------------------------------------------------------------------------------
+console.timeEnd = function(name) {
+ var timeStart = Timers[name];
+ if (!timeStart) {
+ console.warn("unknown timer: " + name);
+ return;
+ }
+
+ var timeElapsed = new Date().valueOf() - timeStart;
+ console.log(name + ": " + timeElapsed + "ms");
+};
+
+//------------------------------------------------------------------------------
+console.timeStamp = noop;
+
+//------------------------------------------------------------------------------
+console.profile = noop;
+
+//------------------------------------------------------------------------------
+console.profileEnd = noop;
+
+//------------------------------------------------------------------------------
+console.count = noop;
+
+//------------------------------------------------------------------------------
+console.exception = console.log;
+
+//------------------------------------------------------------------------------
+console.table = function(data, columns) {
+ console.log("%o", data);
+};
+
+//------------------------------------------------------------------------------
+// return a new function that calls both functions passed as args
+//------------------------------------------------------------------------------
+function wrappedOrigCall(orgFunc, newFunc) {
+ return function() {
+ var args = [].slice.call(arguments);
+ try { orgFunc.apply(WinConsole, args); } catch (e) {}
+ try { newFunc.apply(console, args); } catch (e) {}
+ };
+}
+
+//------------------------------------------------------------------------------
+// For every function that exists in the original console object, that
+// also exists in the new console object, wrap the new console method
+// with one that calls both
+//------------------------------------------------------------------------------
+for (var key in console) {
+ if (typeof WinConsole[key] == "function") {
+ console[key] = wrappedOrigCall(WinConsole[key], console[key]);
+ }
+}
+
+});
+
+// file: lib/common/plugin/contacts.js
+define("cordova/plugin/contacts", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ ContactError = require('cordova/plugin/ContactError'),
+ utils = require('cordova/utils'),
+ Contact = require('cordova/plugin/Contact');
+
+/**
+* Represents a group of Contacts.
+* @constructor
+*/
+var contacts = {
+ /**
+ * Returns an array of Contacts matching the search criteria.
+ * @param fields that should be searched
+ * @param successCB success callback
+ * @param errorCB error callback
+ * @param {ContactFindOptions} options that can be applied to contact searching
+ * @return array of Contacts matching search criteria
+ */
+ find:function(fields, successCB, errorCB, options) {
+ argscheck.checkArgs('afFO', 'contacts.find', arguments);
+ if (!fields.length) {
+ errorCB && errorCB(new ContactError(ContactError.INVALID_ARGUMENT_ERROR));
+ } else {
+ var win = function(result) {
+ var cs = [];
+ for (var i = 0, l = result.length; i < l; i++) {
+ cs.push(contacts.create(result[i]));
+ }
+ successCB(cs);
+ };
+ exec(win, errorCB, "Contacts", "search", [fields, options]);
+ }
+ },
+
+ /**
+ * This function creates a new contact, but it does not persist the contact
+ * to device storage. To persist the contact to device storage, invoke
+ * contact.save().
+ * @param properties an object whose properties will be examined to create a new Contact
+ * @returns new Contact object
+ */
+ create:function(properties) {
+ argscheck.checkArgs('O', 'contacts.create', arguments);
+ var contact = new Contact();
+ for (var i in properties) {
+ if (typeof contact[i] !== 'undefined' && properties.hasOwnProperty(i)) {
+ contact[i] = properties[i];
+ }
+ }
+ return contact;
+ }
+};
+
+module.exports = contacts;
+
+});
+
+// file: lib/common/plugin/contacts/symbols.js
+define("cordova/plugin/contacts/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/contacts', 'navigator.contacts');
+modulemapper.clobbers('cordova/plugin/Contact', 'Contact');
+modulemapper.clobbers('cordova/plugin/ContactAddress', 'ContactAddress');
+modulemapper.clobbers('cordova/plugin/ContactError', 'ContactError');
+modulemapper.clobbers('cordova/plugin/ContactField', 'ContactField');
+modulemapper.clobbers('cordova/plugin/ContactFindOptions', 'ContactFindOptions');
+modulemapper.clobbers('cordova/plugin/ContactName', 'ContactName');
+modulemapper.clobbers('cordova/plugin/ContactOrganization', 'ContactOrganization');
+
+});
+
+// file: lib/common/plugin/device.js
+define("cordova/plugin/device", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ channel = require('cordova/channel'),
+ utils = require('cordova/utils'),
+ exec = require('cordova/exec');
+
+// Tell cordova channel to wait on the CordovaInfoReady event
+channel.waitForInitialization('onCordovaInfoReady');
+
+/**
+ * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the
+ * phone, etc.
+ * @constructor
+ */
+function Device() {
+ this.available = false;
+ this.platform = null;
+ this.version = null;
+ this.name = null;
+ this.uuid = null;
+ this.cordova = null;
+ this.model = null;
+
+ var me = this;
+
+ channel.onCordovaReady.subscribe(function() {
+ me.getInfo(function(info) {
+ me.available = true;
+ me.platform = info.platform;
+ me.version = info.version;
+ me.name = info.name;
+ me.uuid = info.uuid;
+ me.cordova = info.cordova;
+ me.model = info.model;
+ channel.onCordovaInfoReady.fire();
+ },function(e) {
+ me.available = false;
+ utils.alert("[ERROR] Error initializing Cordova: " + e);
+ });
+ });
+}
+
+/**
+ * Get device info
+ *
+ * @param {Function} successCallback The function to call when the heading data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL)
+ */
+Device.prototype.getInfo = function(successCallback, errorCallback) {
+ argscheck.checkArgs('fF', 'Device.getInfo', arguments);
+ exec(successCallback, errorCallback, "Device", "getDeviceInfo", []);
+};
+
+module.exports = new Device();
+
+});
+
+// file: lib/common/plugin/device/symbols.js
+define("cordova/plugin/device/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/device', 'device');
+
+});
+
+// file: lib/common/plugin/echo.js
+define("cordova/plugin/echo", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback.
+ * @param successCallback invoked with a FileSystem object
+ * @param errorCallback invoked if error occurs retrieving file system
+ * @param message The string to be echoed.
+ * @param forceAsync Whether to force an async return value (for testing native->js bridge).
+ */
+module.exports = function(successCallback, errorCallback, message, forceAsync) {
+ var action = forceAsync ? 'echoAsync' : 'echo';
+ if (!forceAsync && message.constructor == ArrayBuffer) {
+ action = 'echoArrayBuffer';
+ }
+ exec(successCallback, errorCallback, "Echo", action, [message]);
+};
+
+
+});
+
+// file: lib/ios/plugin/file/symbols.js
+define("cordova/plugin/file/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper'),
+ symbolshelper = require('cordova/plugin/file/symbolshelper');
+
+symbolshelper(modulemapper.clobbers);
+modulemapper.merges('cordova/plugin/ios/Entry', 'Entry');
+
+});
+
+// file: lib/common/plugin/file/symbolshelper.js
+define("cordova/plugin/file/symbolshelper", function(require, exports, module) {
+
+module.exports = function(exportFunc) {
+ exportFunc('cordova/plugin/DirectoryEntry', 'DirectoryEntry');
+ exportFunc('cordova/plugin/DirectoryReader', 'DirectoryReader');
+ exportFunc('cordova/plugin/Entry', 'Entry');
+ exportFunc('cordova/plugin/File', 'File');
+ exportFunc('cordova/plugin/FileEntry', 'FileEntry');
+ exportFunc('cordova/plugin/FileError', 'FileError');
+ exportFunc('cordova/plugin/FileReader', 'FileReader');
+ exportFunc('cordova/plugin/FileSystem', 'FileSystem');
+ exportFunc('cordova/plugin/FileUploadOptions', 'FileUploadOptions');
+ exportFunc('cordova/plugin/FileUploadResult', 'FileUploadResult');
+ exportFunc('cordova/plugin/FileWriter', 'FileWriter');
+ exportFunc('cordova/plugin/Flags', 'Flags');
+ exportFunc('cordova/plugin/LocalFileSystem', 'LocalFileSystem');
+ exportFunc('cordova/plugin/Metadata', 'Metadata');
+ exportFunc('cordova/plugin/ProgressEvent', 'ProgressEvent');
+ exportFunc('cordova/plugin/requestFileSystem', 'requestFileSystem');
+ exportFunc('cordova/plugin/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI');
+};
+
+});
+
+// file: lib/common/plugin/filetransfer/symbols.js
+define("cordova/plugin/filetransfer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/FileTransfer', 'FileTransfer');
+modulemapper.clobbers('cordova/plugin/FileTransferError', 'FileTransferError');
+
+});
+
+// file: lib/common/plugin/geolocation.js
+define("cordova/plugin/geolocation", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ PositionError = require('cordova/plugin/PositionError'),
+ Position = require('cordova/plugin/Position');
+
+var timers = {}; // list of timers in use
+
+// Returns default params, overrides if provided with values
+function parseParameters(options) {
+ var opt = {
+ maximumAge: 0,
+ enableHighAccuracy: false,
+ timeout: Infinity
+ };
+
+ if (options) {
+ if (options.maximumAge !== undefined && !isNaN(options.maximumAge) && options.maximumAge > 0) {
+ opt.maximumAge = options.maximumAge;
+ }
+ if (options.enableHighAccuracy !== undefined) {
+ opt.enableHighAccuracy = options.enableHighAccuracy;
+ }
+ if (options.timeout !== undefined && !isNaN(options.timeout)) {
+ if (options.timeout < 0) {
+ opt.timeout = 0;
+ } else {
+ opt.timeout = options.timeout;
+ }
+ }
+ }
+
+ return opt;
+}
+
+// Returns a timeout failure, closed over a specified timeout value and error callback.
+function createTimeout(errorCallback, timeout) {
+ var t = setTimeout(function() {
+ clearTimeout(t);
+ t = null;
+ errorCallback({
+ code:PositionError.TIMEOUT,
+ message:"Position retrieval timed out."
+ });
+ }, timeout);
+ return t;
+}
+
+var geolocation = {
+ lastPosition:null, // reference to last known (cached) position returned
+ /**
+ * Asynchronously acquires the current position.
+ *
+ * @param {Function} successCallback The function to call when the position data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the heading position. (OPTIONAL)
+ * @param {PositionOptions} options The options for getting the position data. (OPTIONAL)
+ */
+ getCurrentPosition:function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments);
+ options = parseParameters(options);
+
+ // Timer var that will fire an error callback if no position is retrieved from native
+ // before the "timeout" param provided expires
+ var timeoutTimer = {timer:null};
+
+ var win = function(p) {
+ clearTimeout(timeoutTimer.timer);
+ if (!(timeoutTimer.timer)) {
+ // Timeout already happened, or native fired error callback for
+ // this geo request.
+ // Don't continue with success callback.
+ return;
+ }
+ var pos = new Position(
+ {
+ latitude:p.latitude,
+ longitude:p.longitude,
+ altitude:p.altitude,
+ accuracy:p.accuracy,
+ heading:p.heading,
+ velocity:p.velocity,
+ altitudeAccuracy:p.altitudeAccuracy
+ },
+ (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp)))
+ );
+ geolocation.lastPosition = pos;
+ successCallback(pos);
+ };
+ var fail = function(e) {
+ clearTimeout(timeoutTimer.timer);
+ timeoutTimer.timer = null;
+ var err = new PositionError(e.code, e.message);
+ if (errorCallback) {
+ errorCallback(err);
+ }
+ };
+
+ // Check our cached position, if its timestamp difference with current time is less than the maximumAge, then just
+ // fire the success callback with the cached position.
+ if (geolocation.lastPosition && options.maximumAge && (((new Date()).getTime() - geolocation.lastPosition.timestamp.getTime()) <= options.maximumAge)) {
+ successCallback(geolocation.lastPosition);
+ // If the cached position check failed and the timeout was set to 0, error out with a TIMEOUT error object.
+ } else if (options.timeout === 0) {
+ fail({
+ code:PositionError.TIMEOUT,
+ message:"timeout value in PositionOptions set to 0 and no cached Position object available, or cached Position object's age exceeds provided PositionOptions' maximumAge parameter."
+ });
+ // Otherwise we have to call into native to retrieve a position.
+ } else {
+ if (options.timeout !== Infinity) {
+ // If the timeout value was not set to Infinity (default), then
+ // set up a timeout function that will fire the error callback
+ // if no successful position was retrieved before timeout expired.
+ timeoutTimer.timer = createTimeout(fail, options.timeout);
+ } else {
+ // This is here so the check in the win function doesn't mess stuff up
+ // may seem weird but this guarantees timeoutTimer is
+ // always truthy before we call into native
+ timeoutTimer.timer = true;
+ }
+ exec(win, fail, "Geolocation", "getLocation", [options.enableHighAccuracy, options.maximumAge]);
+ }
+ return timeoutTimer;
+ },
+ /**
+ * Asynchronously watches the geolocation for changes to geolocation. When a change occurs,
+ * the successCallback is called with the new location.
+ *
+ * @param {Function} successCallback The function to call each time the location data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the location data. (OPTIONAL)
+ * @param {PositionOptions} options The options for getting the location data such as frequency. (OPTIONAL)
+ * @return String The watch id that must be passed to #clearWatch to stop watching.
+ */
+ watchPosition:function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments);
+ options = parseParameters(options);
+
+ var id = utils.createUUID();
+
+ // Tell device to get a position ASAP, and also retrieve a reference to the timeout timer generated in getCurrentPosition
+ timers[id] = geolocation.getCurrentPosition(successCallback, errorCallback, options);
+
+ var fail = function(e) {
+ clearTimeout(timers[id].timer);
+ var err = new PositionError(e.code, e.message);
+ if (errorCallback) {
+ errorCallback(err);
+ }
+ };
+
+ var win = function(p) {
+ clearTimeout(timers[id].timer);
+ if (options.timeout !== Infinity) {
+ timers[id].timer = createTimeout(fail, options.timeout);
+ }
+ var pos = new Position(
+ {
+ latitude:p.latitude,
+ longitude:p.longitude,
+ altitude:p.altitude,
+ accuracy:p.accuracy,
+ heading:p.heading,
+ velocity:p.velocity,
+ altitudeAccuracy:p.altitudeAccuracy
+ },
+ (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp)))
+ );
+ geolocation.lastPosition = pos;
+ successCallback(pos);
+ };
+
+ exec(win, fail, "Geolocation", "addWatch", [id, options.enableHighAccuracy]);
+
+ return id;
+ },
+ /**
+ * Clears the specified heading watch.
+ *
+ * @param {String} id The ID of the watch returned from #watchPosition
+ */
+ clearWatch:function(id) {
+ if (id && timers[id] !== undefined) {
+ clearTimeout(timers[id].timer);
+ timers[id].timer = false;
+ exec(null, null, "Geolocation", "clearWatch", [id]);
+ }
+ }
+};
+
+module.exports = geolocation;
+
+});
+
+// file: lib/common/plugin/geolocation/symbols.js
+define("cordova/plugin/geolocation/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/geolocation', 'navigator.geolocation');
+modulemapper.clobbers('cordova/plugin/PositionError', 'PositionError');
+modulemapper.clobbers('cordova/plugin/Position', 'Position');
+modulemapper.clobbers('cordova/plugin/Coordinates', 'Coordinates');
+
+});
+
+// file: lib/common/plugin/globalization.js
+define("cordova/plugin/globalization", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ GlobalizationError = require('cordova/plugin/GlobalizationError');
+
+var globalization = {
+
+/**
+* Returns the string identifier for the client's current language.
+* It returns the language identifier string to the successCB callback with a
+* properties object as a parameter. If there is an error getting the language,
+* then the errorCB callback is invoked.
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.value {String}: The language identifier
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+* globalization.getPreferredLanguage(function (language) {alert('language:' + language.value + '\n');},
+* function () {});
+*/
+getPreferredLanguage:function(successCB, failureCB) {
+ argscheck.checkArgs('fF', 'Globalization.getPreferredLanguage', arguments);
+ exec(successCB, failureCB, "Globalization","getPreferredLanguage", []);
+},
+
+/**
+* Returns the string identifier for the client's current locale setting.
+* It returns the locale identifier string to the successCB callback with a
+* properties object as a parameter. If there is an error getting the locale,
+* then the errorCB callback is invoked.
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.value {String}: The locale identifier
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+* globalization.getLocaleName(function (locale) {alert('locale:' + locale.value + '\n');},
+* function () {});
+*/
+getLocaleName:function(successCB, failureCB) {
+ argscheck.checkArgs('fF', 'Globalization.getLocaleName', arguments);
+ exec(successCB, failureCB, "Globalization","getLocaleName", []);
+},
+
+
+/**
+* Returns a date formatted as a string according to the client's user preferences and
+* calendar using the time zone of the client. It returns the formatted date string to the
+* successCB callback with a properties object as a parameter. If there is an error
+* formatting the date, then the errorCB callback is invoked.
+*
+* The defaults are: formatLenght="short" and selector="date and time"
+*
+* @param {Date} date
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+* formatLength {String}: 'short', 'medium', 'long', or 'full'
+* selector {String}: 'date', 'time', or 'date and time'
+*
+* @return Object.value {String}: The localized date string
+*
+* @error GlobalizationError.FORMATTING_ERROR
+*
+* Example
+* globalization.dateToString(new Date(),
+* function (date) {alert('date:' + date.value + '\n');},
+* function (errorCode) {alert(errorCode);},
+* {formatLength:'short'});
+*/
+dateToString:function(date, successCB, failureCB, options) {
+ argscheck.checkArgs('dfFO', 'Globalization.dateToString', arguments);
+ var dateValue = date.valueOf();
+ exec(successCB, failureCB, "Globalization", "dateToString", [{"date": dateValue, "options": options}]);
+},
+
+
+/**
+* Parses a date formatted as a string according to the client's user
+* preferences and calendar using the time zone of the client and returns
+* the corresponding date object. It returns the date to the successCB
+* callback with a properties object as a parameter. If there is an error
+* parsing the date string, then the errorCB callback is invoked.
+*
+* The defaults are: formatLength="short" and selector="date and time"
+*
+* @param {String} dateString
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+* formatLength {String}: 'short', 'medium', 'long', or 'full'
+* selector {String}: 'date', 'time', or 'date and time'
+*
+* @return Object.year {Number}: The four digit year
+* Object.month {Number}: The month from (0 - 11)
+* Object.day {Number}: The day from (1 - 31)
+* Object.hour {Number}: The hour from (0 - 23)
+* Object.minute {Number}: The minute from (0 - 59)
+* Object.second {Number}: The second from (0 - 59)
+* Object.millisecond {Number}: The milliseconds (from 0 - 999),
+* not available on all platforms
+*
+* @error GlobalizationError.PARSING_ERROR
+*
+* Example
+* globalization.stringToDate('4/11/2011',
+* function (date) { alert('Month:' + date.month + '\n' +
+* 'Day:' + date.day + '\n' +
+* 'Year:' + date.year + '\n');},
+* function (errorCode) {alert(errorCode);},
+* {selector:'date'});
+*/
+stringToDate:function(dateString, successCB, failureCB, options) {
+ argscheck.checkArgs('sfFO', 'Globalization.stringToDate', arguments);
+ exec(successCB, failureCB, "Globalization", "stringToDate", [{"dateString": dateString, "options": options}]);
+},
+
+
+/**
+* Returns a pattern string for formatting and parsing dates according to the client's
+* user preferences. It returns the pattern to the successCB callback with a
+* properties object as a parameter. If there is an error obtaining the pattern,
+* then the errorCB callback is invoked.
+*
+* The defaults are: formatLength="short" and selector="date and time"
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+* formatLength {String}: 'short', 'medium', 'long', or 'full'
+* selector {String}: 'date', 'time', or 'date and time'
+*
+* @return Object.pattern {String}: The date and time pattern for formatting and parsing dates.
+* The patterns follow Unicode Technical Standard #35
+* http://unicode.org/reports/tr35/tr35-4.html
+* Object.timezone {String}: The abbreviated name of the time zone on the client
+* Object.utc_offset {Number}: The current difference in seconds between the client's
+* time zone and coordinated universal time.
+* Object.dst_offset {Number}: The current daylight saving time offset in seconds
+* between the client's non-daylight saving's time zone
+* and the client's daylight saving's time zone.
+*
+* @error GlobalizationError.PATTERN_ERROR
+*
+* Example
+* globalization.getDatePattern(
+* function (date) {alert('pattern:' + date.pattern + '\n');},
+* function () {},
+* {formatLength:'short'});
+*/
+getDatePattern:function(successCB, failureCB, options) {
+ argscheck.checkArgs('fFO', 'Globalization.getDatePattern', arguments);
+ exec(successCB, failureCB, "Globalization", "getDatePattern", [{"options": options}]);
+},
+
+
+/**
+* Returns an array of either the names of the months or days of the week
+* according to the client's user preferences and calendar. It returns the array of names to the
+* successCB callback with a properties object as a parameter. If there is an error obtaining the
+* names, then the errorCB callback is invoked.
+*
+* The defaults are: type="wide" and item="months"
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+* type {String}: 'narrow' or 'wide'
+* item {String}: 'months', or 'days'
+*
+* @return Object.value {Array{String}}: The array of names starting from either
+* the first month in the year or the
+* first day of the week.
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+* globalization.getDateNames(function (names) {
+* for(var i = 0; i < names.value.length; i++) {
+* alert('Month:' + names.value[i] + '\n');}},
+* function () {});
+*/
+getDateNames:function(successCB, failureCB, options) {
+ argscheck.checkArgs('fFO', 'Globalization.getDateNames', arguments);
+ exec(successCB, failureCB, "Globalization", "getDateNames", [{"options": options}]);
+},
+
+/**
+* Returns whether daylight savings time is in effect for a given date using the client's
+* time zone and calendar. It returns whether or not daylight savings time is in effect
+* to the successCB callback with a properties object as a parameter. If there is an error
+* reading the date, then the errorCB callback is invoked.
+*
+* @param {Date} date
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.dst {Boolean}: The value "true" indicates that daylight savings time is
+* in effect for the given date and "false" indicate that it is not.
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+* globalization.isDayLightSavingsTime(new Date(),
+* function (date) {alert('dst:' + date.dst + '\n');}
+* function () {});
+*/
+isDayLightSavingsTime:function(date, successCB, failureCB) {
+ argscheck.checkArgs('dfF', 'Globalization.isDayLightSavingsTime', arguments);
+ var dateValue = date.valueOf();
+ exec(successCB, failureCB, "Globalization", "isDayLightSavingsTime", [{"date": dateValue}]);
+},
+
+/**
+* Returns the first day of the week according to the client's user preferences and calendar.
+* The days of the week are numbered starting from 1 where 1 is considered to be Sunday.
+* It returns the day to the successCB callback with a properties object as a parameter.
+* If there is an error obtaining the pattern, then the errorCB callback is invoked.
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.value {Number}: The number of the first day of the week.
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+* globalization.getFirstDayOfWeek(function (day)
+* { alert('Day:' + day.value + '\n');},
+* function () {});
+*/
+getFirstDayOfWeek:function(successCB, failureCB) {
+ argscheck.checkArgs('fF', 'Globalization.getFirstDayOfWeek', arguments);
+ exec(successCB, failureCB, "Globalization", "getFirstDayOfWeek", []);
+},
+
+
+/**
+* Returns a number formatted as a string according to the client's user preferences.
+* It returns the formatted number string to the successCB callback with a properties object as a
+* parameter. If there is an error formatting the number, then the errorCB callback is invoked.
+*
+* The defaults are: type="decimal"
+*
+* @param {Number} number
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+* type {String}: 'decimal', "percent", or 'currency'
+*
+* @return Object.value {String}: The formatted number string.
+*
+* @error GlobalizationError.FORMATTING_ERROR
+*
+* Example
+* globalization.numberToString(3.25,
+* function (number) {alert('number:' + number.value + '\n');},
+* function () {},
+* {type:'decimal'});
+*/
+numberToString:function(number, successCB, failureCB, options) {
+ argscheck.checkArgs('nfFO', 'Globalization.numberToString', arguments);
+ exec(successCB, failureCB, "Globalization", "numberToString", [{"number": number, "options": options}]);
+},
+
+/**
+* Parses a number formatted as a string according to the client's user preferences and
+* returns the corresponding number. It returns the number to the successCB callback with a
+* properties object as a parameter. If there is an error parsing the number string, then
+* the errorCB callback is invoked.
+*
+* The defaults are: type="decimal"
+*
+* @param {String} numberString
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+* type {String}: 'decimal', "percent", or 'currency'
+*
+* @return Object.value {Number}: The parsed number.
+*
+* @error GlobalizationError.PARSING_ERROR
+*
+* Example
+* globalization.stringToNumber('1234.56',
+* function (number) {alert('Number:' + number.value + '\n');},
+* function () { alert('Error parsing number');});
+*/
+stringToNumber:function(numberString, successCB, failureCB, options) {
+ argscheck.checkArgs('sfFO', 'Globalization.stringToNumber', arguments);
+ exec(successCB, failureCB, "Globalization", "stringToNumber", [{"numberString": numberString, "options": options}]);
+},
+
+/**
+* Returns a pattern string for formatting and parsing numbers according to the client's user
+* preferences. It returns the pattern to the successCB callback with a properties object as a
+* parameter. If there is an error obtaining the pattern, then the errorCB callback is invoked.
+*
+* The defaults are: type="decimal"
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+* type {String}: 'decimal', "percent", or 'currency'
+*
+* @return Object.pattern {String}: The number pattern for formatting and parsing numbers.
+* The patterns follow Unicode Technical Standard #35.
+* http://unicode.org/reports/tr35/tr35-4.html
+* Object.symbol {String}: The symbol to be used when formatting and parsing
+* e.g., percent or currency symbol.
+* Object.fraction {Number}: The number of fractional digits to use when parsing and
+* formatting numbers.
+* Object.rounding {Number}: The rounding increment to use when parsing and formatting.
+* Object.positive {String}: The symbol to use for positive numbers when parsing and formatting.
+* Object.negative: {String}: The symbol to use for negative numbers when parsing and formatting.
+* Object.decimal: {String}: The decimal symbol to use for parsing and formatting.
+* Object.grouping: {String}: The grouping symbol to use for parsing and formatting.
+*
+* @error GlobalizationError.PATTERN_ERROR
+*
+* Example
+* globalization.getNumberPattern(
+* function (pattern) {alert('Pattern:' + pattern.pattern + '\n');},
+* function () {});
+*/
+getNumberPattern:function(successCB, failureCB, options) {
+ argscheck.checkArgs('fFO', 'Globalization.getNumberPattern', arguments);
+ exec(successCB, failureCB, "Globalization", "getNumberPattern", [{"options": options}]);
+},
+
+/**
+* Returns a pattern string for formatting and parsing currency values according to the client's
+* user preferences and ISO 4217 currency code. It returns the pattern to the successCB callback with a
+* properties object as a parameter. If there is an error obtaining the pattern, then the errorCB
+* callback is invoked.
+*
+* @param {String} currencyCode
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.pattern {String}: The currency pattern for formatting and parsing currency values.
+* The patterns follow Unicode Technical Standard #35
+* http://unicode.org/reports/tr35/tr35-4.html
+* Object.code {String}: The ISO 4217 currency code for the pattern.
+* Object.fraction {Number}: The number of fractional digits to use when parsing and
+* formatting currency.
+* Object.rounding {Number}: The rounding increment to use when parsing and formatting.
+* Object.decimal: {String}: The decimal symbol to use for parsing and formatting.
+* Object.grouping: {String}: The grouping symbol to use for parsing and formatting.
+*
+* @error GlobalizationError.FORMATTING_ERROR
+*
+* Example
+* globalization.getCurrencyPattern('EUR',
+* function (currency) {alert('Pattern:' + currency.pattern + '\n');}
+* function () {});
+*/
+getCurrencyPattern:function(currencyCode, successCB, failureCB) {
+ argscheck.checkArgs('sfF', 'Globalization.getCurrencyPattern', arguments);
+ exec(successCB, failureCB, "Globalization", "getCurrencyPattern", [{"currencyCode": currencyCode}]);
+}
+
+};
+
+module.exports = globalization;
+
+});
+
+// file: lib/common/plugin/globalization/symbols.js
+define("cordova/plugin/globalization/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/globalization', 'navigator.globalization');
+modulemapper.clobbers('cordova/plugin/GlobalizationError', 'GlobalizationError');
+
+});
+
+// file: lib/ios/plugin/inappbrowser/symbols.js
+define("cordova/plugin/inappbrowser/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/InAppBrowser', 'open');
+
+});
+
+// file: lib/ios/plugin/ios/Contact.js
+define("cordova/plugin/ios/Contact", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ ContactError = require('cordova/plugin/ContactError');
+
+/**
+ * Provides iOS Contact.display API.
+ */
+module.exports = {
+ display : function(errorCB, options) {
+ /*
+ * Display a contact using the iOS Contact Picker UI
+ * NOT part of W3C spec so no official documentation
+ *
+ * @param errorCB error callback
+ * @param options object
+ * allowsEditing: boolean AS STRING
+ * "true" to allow editing the contact
+ * "false" (default) display contact
+ */
+
+ if (this.id === null) {
+ if (typeof errorCB === "function") {
+ var errorObj = new ContactError(ContactError.UNKNOWN_ERROR);
+ errorCB(errorObj);
+ }
+ }
+ else {
+ exec(null, errorCB, "Contacts","displayContact", [this.id, options]);
+ }
+ }
+};
+
+});
+
+// file: lib/ios/plugin/ios/Entry.js
+define("cordova/plugin/ios/Entry", function(require, exports, module) {
+
+module.exports = {
+ toURL:function() {
+ // TODO: refactor path in a cross-platform way so we can eliminate
+ // these kinds of platform-specific hacks.
+ return "file://localhost" + this.fullPath;
+ },
+ toURI: function() {
+ console.log("DEPRECATED: Update your code to use 'toURL'");
+ return "file://localhost" + this.fullPath;
+ }
+};
+
+});
+
+// file: lib/ios/plugin/ios/console.js
+define("cordova/plugin/ios/console", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * create a nice string for an object
+ */
+function stringify(message) {
+ try {
+ if (typeof message === "object" && JSON && JSON.stringify) {
+ try {
+ return JSON.stringify(message);
+ }
+ catch (e) {
+ return "error JSON.stringify()ing argument: " + e;
+ }
+ } else {
+ return message.toString();
+ }
+ } catch (e) {
+ return e.toString();
+ }
+}
+
+/**
+ * Wrapper one of the console logging methods, so that
+ * the Cordova logging native is called, then the original.
+ */
+function wrappedMethod(console, method) {
+ var origMethod = console[method];
+
+ return function(message) {
+ exec(null, null,
+ 'Debug Console', 'log',
+ [ stringify(message), { logLevel: method.toUpperCase() } ]
+ );
+
+ if (!origMethod) return;
+
+ origMethod.apply(console, arguments);
+ };
+}
+
+var console = window.console || {};
+
+// 2012-10-06 pmuellr - marking setLevel() method and logLevel property
+// on console as deprecated;
+// it didn't do anything useful, since the level constants weren't accessible
+// to anyone
+
+console.setLevel = function() {};
+console.logLevel = 0;
+
+// wrapper the logging messages
+
+var methods = ["log", "debug", "info", "warn", "error"];
+
+for (var i=0; i<methods.length; i++) {
+ var method = methods[i];
+
+ console[method] = wrappedMethod(console, method);
+}
+
+module.exports = console;
+
+});
+
+// file: lib/ios/plugin/ios/console/symbols.js
+define("cordova/plugin/ios/console/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/ios/console', 'console');
+
+});
+
+// file: lib/ios/plugin/ios/contacts.js
+define("cordova/plugin/ios/contacts", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * Provides iOS enhanced contacts API.
+ */
+module.exports = {
+ newContactUI : function(successCallback) {
+ /*
+ * Create a contact using the iOS Contact Picker UI
+ * NOT part of W3C spec so no official documentation
+ *
+ * returns: the id of the created contact as param to successCallback
+ */
+ exec(successCallback, null, "Contacts","newContact", []);
+ },
+ chooseContact : function(successCallback, options) {
+ /*
+ * Select a contact using the iOS Contact Picker UI
+ * NOT part of W3C spec so no official documentation
+ *
+ * @param errorCB error callback
+ * @param options object
+ * allowsEditing: boolean AS STRING
+ * "true" to allow editing the contact
+ * "false" (default) display contact
+ * fields: array of fields to return in contact object (see ContactOptions.fields)
+ *
+ * @returns
+ * id of contact selected
+ * ContactObject
+ * if no fields provided contact contains just id information
+ * if fields provided contact object contains information for the specified fields
+ *
+ */
+ var win = function(result) {
+ var fullContact = require('cordova/plugin/contacts').create(result);
+ successCallback(fullContact.id, fullContact);
+ };
+ exec(win, null, "Contacts","chooseContact", [options]);
+ }
+};
+
+});
+
+// file: lib/ios/plugin/ios/contacts/symbols.js
+define("cordova/plugin/ios/contacts/symbols", function(require, exports, module) {
+
+require('cordova/plugin/contacts/symbols');
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.merges('cordova/plugin/ios/contacts', 'navigator.contacts');
+modulemapper.merges('cordova/plugin/ios/Contact', 'Contact');
+
+});
+
+// file: lib/ios/plugin/ios/geolocation/symbols.js
+define("cordova/plugin/ios/geolocation/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.merges('cordova/plugin/geolocation', 'navigator.geolocation');
+
+});
+
+// file: lib/ios/plugin/ios/logger/plugininit.js
+define("cordova/plugin/ios/logger/plugininit", function(require, exports, module) {
+
+// use the native logger
+var logger = require("cordova/plugin/logger");
+logger.useConsole(false);
+
+});
+
+// file: lib/ios/plugin/ios/notification.js
+define("cordova/plugin/ios/notification", function(require, exports, module) {
+
+var Media = require('cordova/plugin/Media');
+
+module.exports = {
+ beep:function(count) {
+ (new Media('beep.wav')).play();
+ }
+};
+
+});
+
+// file: lib/common/plugin/logger.js
+define("cordova/plugin/logger", function(require, exports, module) {
+
+//------------------------------------------------------------------------------
+// The logger module exports the following properties/functions:
+//
+// LOG - constant for the level LOG
+// ERROR - constant for the level ERROR
+// WARN - constant for the level WARN
+// INFO - constant for the level INFO
+// DEBUG - constant for the level DEBUG
+// logLevel() - returns current log level
+// logLevel(value) - sets and returns a new log level
+// useConsole() - returns whether logger is using console
+// useConsole(value) - sets and returns whether logger is using console
+// log(message,...) - logs a message at level LOG
+// error(message,...) - logs a message at level ERROR
+// warn(message,...) - logs a message at level WARN
+// info(message,...) - logs a message at level INFO
+// debug(message,...) - logs a message at level DEBUG
+// logLevel(level,message,...) - logs a message specified level
+//
+//------------------------------------------------------------------------------
+
+var logger = exports;
+
+var exec = require('cordova/exec');
+var utils = require('cordova/utils');
+
+var UseConsole = true;
+var Queued = [];
+var DeviceReady = false;
+var CurrentLevel;
+
+/**
+ * Logging levels
+ */
+
+var Levels = [
+ "LOG",
+ "ERROR",
+ "WARN",
+ "INFO",
+ "DEBUG"
+];
+
+/*
+ * add the logging levels to the logger object and
+ * to a separate levelsMap object for testing
+ */
+
+var LevelsMap = {};
+for (var i=0; i<Levels.length; i++) {
+ var level = Levels[i];
+ LevelsMap[level] = i;
+ logger[level] = level;
+}
+
+CurrentLevel = LevelsMap.WARN;
+
+/**
+ * Getter/Setter for the logging level
+ *
+ * Returns the current logging level.
+ *
+ * When a value is passed, sets the logging level to that value.
+ * The values should be one of the following constants:
+ * logger.LOG
+ * logger.ERROR
+ * logger.WARN
+ * logger.INFO
+ * logger.DEBUG
+ *
+ * The value used determines which messages get printed. The logging
+ * values above are in order, and only messages logged at the logging
+ * level or above will actually be displayed to the user. E.g., the
+ * default level is WARN, so only messages logged with LOG, ERROR, or
+ * WARN will be displayed; INFO and DEBUG messages will be ignored.
+ */
+logger.level = function (value) {
+ if (arguments.length) {
+ if (LevelsMap[value] === null) {
+ throw new Error("invalid logging level: " + value);
+ }
+ CurrentLevel = LevelsMap[value];
+ }
+
+ return Levels[CurrentLevel];
+};
+
+/**
+ * Getter/Setter for the useConsole functionality
+ *
+ * When useConsole is true, the logger will log via the
+ * browser 'console' object. Otherwise, it will use the
+ * native Logger plugin.
+ */
+logger.useConsole = function (value) {
+ if (arguments.length) UseConsole = !!value;
+
+ if (UseConsole) {
+ if (typeof console == "undefined") {
+ throw new Error("global console object is not defined");
+ }
+
+ if (typeof console.log != "function") {
+ throw new Error("global console object does not have a log function");
+ }
+
+ if (typeof console.useLogger == "function") {
+ if (console.useLogger()) {
+ throw new Error("console and logger are too intertwingly");
+ }
+ }
+ }
+
+ return UseConsole;
+};
+
+/**
+ * Logs a message at the LOG level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.log = function(message) { logWithArgs("LOG", arguments); };
+
+/**
+ * Logs a message at the ERROR level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.error = function(message) { logWithArgs("ERROR", arguments); };
+
+/**
+ * Logs a message at the WARN level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.warn = function(message) { logWithArgs("WARN", arguments); };
+
+/**
+ * Logs a message at the INFO level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.info = function(message) { logWithArgs("INFO", arguments); };
+
+/**
+ * Logs a message at the DEBUG level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.debug = function(message) { logWithArgs("DEBUG", arguments); };
+
+// log at the specified level with args
+function logWithArgs(level, args) {
+ args = [level].concat([].slice.call(args));
+ logger.logLevel.apply(logger, args);
+}
+
+/**
+ * Logs a message at the specified level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.logLevel = function(level, message /* , ... */) {
+ // format the message with the parameters
+ var formatArgs = [].slice.call(arguments, 2);
+ message = utils.vformat(message, formatArgs);
+
+ if (LevelsMap[level] === null) {
+ throw new Error("invalid logging level: " + level);
+ }
+
+ if (LevelsMap[level] > CurrentLevel) return;
+
+ // queue the message if not yet at deviceready
+ if (!DeviceReady && !UseConsole) {
+ Queued.push([level, message]);
+ return;
+ }
+
+ // if not using the console, use the native logger
+ if (!UseConsole) {
+ exec(null, null, "Logger", "logLevel", [level, message]);
+ return;
+ }
+
+ // make sure console is not using logger
+ if (console.__usingCordovaLogger) {
+ throw new Error("console and logger are too intertwingly");
+ }
+
+ // log to the console
+ switch (level) {
+ case logger.LOG: console.log(message); break;
+ case logger.ERROR: console.log("ERROR: " + message); break;
+ case logger.WARN: console.log("WARN: " + message); break;
+ case logger.INFO: console.log("INFO: " + message); break;
+ case logger.DEBUG: console.log("DEBUG: " + message); break;
+ }
+};
+
+// when deviceready fires, log queued messages
+logger.__onDeviceReady = function() {
+ if (DeviceReady) return;
+
+ DeviceReady = true;
+
+ for (var i=0; i<Queued.length; i++) {
+ var messageArgs = Queued[i];
+ logger.logLevel(messageArgs[0], messageArgs[1]);
+ }
+
+ Queued = null;
+};
+
+// add a deviceready event to log queued messages
+document.addEventListener("deviceready", logger.__onDeviceReady, false);
+
+});
+
+// file: lib/common/plugin/logger/symbols.js
+define("cordova/plugin/logger/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/logger', 'cordova.logger');
+
+});
+
+// file: lib/ios/plugin/media/symbols.js
+define("cordova/plugin/media/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Media', 'Media');
+modulemapper.clobbers('cordova/plugin/MediaError', 'MediaError');
+
+});
+
+// file: lib/common/plugin/network.js
+define("cordova/plugin/network", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ cordova = require('cordova'),
+ channel = require('cordova/channel'),
+ utils = require('cordova/utils');
+
+// Link the onLine property with the Cordova-supplied network info.
+// This works because we clobber the naviagtor object with our own
+// object in bootstrap.js.
+if (typeof navigator != 'undefined') {
+ utils.defineGetter(navigator, 'onLine', function() {
+ return this.connection.type != 'none';
+ });
+}
+
+function NetworkConnection() {
+ this.type = 'unknown';
+}
+
+/**
+ * Get connection info
+ *
+ * @param {Function} successCallback The function to call when the Connection data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the Connection data. (OPTIONAL)
+ */
+NetworkConnection.prototype.getInfo = function(successCallback, errorCallback) {
+ exec(successCallback, errorCallback, "NetworkStatus", "getConnectionInfo", []);
+};
+
+var me = new NetworkConnection();
+var timerId = null;
+var timeout = 500;
+
+channel.onCordovaReady.subscribe(function() {
+ me.getInfo(function(info) {
+ me.type = info;
+ if (info === "none") {
+ // set a timer if still offline at the end of timer send the offline event
+ timerId = setTimeout(function(){
+ cordova.fireDocumentEvent("offline");
+ timerId = null;
+ }, timeout);
+ } else {
+ // If there is a current offline event pending clear it
+ if (timerId !== null) {
+ clearTimeout(timerId);
+ timerId = null;
+ }
+ cordova.fireDocumentEvent("online");
+ }
+
+ // should only fire this once
+ if (channel.onCordovaConnectionReady.state !== 2) {
+ channel.onCordovaConnectionReady.fire();
+ }
+ },
+ function (e) {
+ // If we can't get the network info we should still tell Cordova
+ // to fire the deviceready event.
+ if (channel.onCordovaConnectionReady.state !== 2) {
+ channel.onCordovaConnectionReady.fire();
+ }
+ console.log("Error initializing Network Connection: " + e);
+ });
+});
+
+module.exports = me;
+
+});
+
+// file: lib/common/plugin/networkstatus/symbols.js
+define("cordova/plugin/networkstatus/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/network', 'navigator.network.connection', 'navigator.network.connection is deprecated. Use navigator.connection instead.');
+modulemapper.clobbers('cordova/plugin/network', 'navigator.connection');
+modulemapper.defaults('cordova/plugin/Connection', 'Connection');
+
+});
+
+// file: lib/common/plugin/notification.js
+define("cordova/plugin/notification", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * Provides access to notifications on the device.
+ */
+
+module.exports = {
+
+ /**
+ * Open a native alert dialog, with a customizable title and button text.
+ *
+ * @param {String} message Message to print in the body of the alert
+ * @param {Function} completeCallback The callback that is called when user clicks on a button.
+ * @param {String} title Title of the alert dialog (default: Alert)
+ * @param {String} buttonLabel Label of the close button (default: OK)
+ */
+ alert: function(message, completeCallback, title, buttonLabel) {
+ var _title = (title || "Alert");
+ var _buttonLabel = (buttonLabel || "OK");
+ exec(completeCallback, null, "Notification", "alert", [message, _title, _buttonLabel]);
+ },
+
+ /**
+ * Open a native confirm dialog, with a customizable title and button text.
+ * The result that the user selects is returned to the result callback.
+ *
+ * @param {String} message Message to print in the body of the alert
+ * @param {Function} resultCallback The callback that is called when user clicks on a button.
+ * @param {String} title Title of the alert dialog (default: Confirm)
+ * @param {String} buttonLabels Comma separated list of the labels of the buttons (default: 'OK,Cancel')
+ */
+ confirm: function(message, resultCallback, title, buttonLabels) {
+ var _title = (title || "Confirm");
+ var _buttonLabels = (buttonLabels || "OK,Cancel");
+ exec(resultCallback, null, "Notification", "confirm", [message, _title, _buttonLabels]);
+ },
+
+ /**
+ * Causes the device to vibrate.
+ *
+ * @param {Integer} mills The number of milliseconds to vibrate for.
+ */
+ vibrate: function(mills) {
+ exec(null, null, "Notification", "vibrate", [mills]);
+ },
+
+ /**
+ * Causes the device to beep.
+ * On Android, the default notification ringtone is played "count" times.
+ *
+ * @param {Integer} count The number of beeps.
+ */
+ beep: function(count) {
+ exec(null, null, "Notification", "beep", [count]);
+ }
+};
+
+});
+
+// file: lib/ios/plugin/notification/symbols.js
+define("cordova/plugin/notification/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/notification', 'navigator.notification');
+modulemapper.merges('cordova/plugin/ios/notification', 'navigator.notification');
+
+});
+
+// file: lib/common/plugin/requestFileSystem.js
+define("cordova/plugin/requestFileSystem", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ FileError = require('cordova/plugin/FileError'),
+ FileSystem = require('cordova/plugin/FileSystem'),
+ exec = require('cordova/exec');
+
+/**
+ * Request a file system in which to store application data.
+ * @param type local file system type
+ * @param size indicates how much storage space, in bytes, the application expects to need
+ * @param successCallback invoked with a FileSystem object
+ * @param errorCallback invoked if error occurs retrieving file system
+ */
+var requestFileSystem = function(type, size, successCallback, errorCallback) {
+ argscheck.checkArgs('nnFF', 'requestFileSystem', arguments);
+ var fail = function(code) {
+ errorCallback && errorCallback(new FileError(code));
+ };
+
+ if (type < 0 || type > 3) {
+ fail(FileError.SYNTAX_ERR);
+ } else {
+ // if successful, return a FileSystem object
+ var success = function(file_system) {
+ if (file_system) {
+ if (successCallback) {
+ // grab the name and root from the file system object
+ var result = new FileSystem(file_system.name, file_system.root);
+ successCallback(result);
+ }
+ }
+ else {
+ // no FileSystem object returned
+ fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+ exec(success, fail, "File", "requestFileSystem", [type, size]);
+ }
+};
+
+module.exports = requestFileSystem;
+
+});
+
+// file: lib/common/plugin/resolveLocalFileSystemURI.js
+define("cordova/plugin/resolveLocalFileSystemURI", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ DirectoryEntry = require('cordova/plugin/DirectoryEntry'),
+ FileEntry = require('cordova/plugin/FileEntry'),
+ FileError = require('cordova/plugin/FileError'),
+ exec = require('cordova/exec');
+
+/**
+ * Look up file system Entry referred to by local URI.
+ * @param {DOMString} uri URI referring to a local file or directory
+ * @param successCallback invoked with Entry object corresponding to URI
+ * @param errorCallback invoked if error occurs retrieving file system entry
+ */
+module.exports = function(uri, successCallback, errorCallback) {
+ argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments);
+ // error callback
+ var fail = function(error) {
+ errorCallback && errorCallback(new FileError(error));
+ };
+ // sanity check for 'not:valid:filename'
+ if(!uri || uri.split(":").length > 2) {
+ setTimeout( function() {
+ fail(FileError.ENCODING_ERR);
+ },0);
+ return;
+ }
+ // if successful, return either a file or directory entry
+ var success = function(entry) {
+ var result;
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath) : new FileEntry(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ exec(success, fail, "File", "resolveLocalFileSystemURI", [uri]);
+};
+
+});
+
+// file: lib/common/plugin/splashscreen.js
+define("cordova/plugin/splashscreen", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+var splashscreen = {
+ show:function() {
+ exec(null, null, "SplashScreen", "show", []);
+ },
+ hide:function() {
+ exec(null, null, "SplashScreen", "hide", []);
+ }
+};
+
+module.exports = splashscreen;
+
+});
+
+// file: lib/common/plugin/splashscreen/symbols.js
+define("cordova/plugin/splashscreen/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/splashscreen', 'navigator.splashscreen');
+
+});
+
+// file: lib/common/symbols.js
+define("cordova/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+// Use merges here in case others symbols files depend on this running first,
+// but fail to declare the dependency with a require().
+modulemapper.merges('cordova', 'cordova');
+modulemapper.clobbers('cordova/exec', 'cordova.exec');
+modulemapper.clobbers('cordova/exec', 'Cordova.exec');
+
+});
+
+// file: lib/common/utils.js
+define("cordova/utils", function(require, exports, module) {
+
+var utils = exports;
+
+/**
+ * Defines a property getter / setter for obj[key].
+ */
+utils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) {
+ if (Object.defineProperty) {
+ var desc = {
+ get: getFunc,
+ configurable: true
+ };
+ if (opt_setFunc) {
+ desc.set = opt_setFunc;
+ }
+ Object.defineProperty(obj, key, desc);
+ } else {
+ obj.__defineGetter__(key, getFunc);
+ if (opt_setFunc) {
+ obj.__defineSetter__(key, opt_setFunc);
+ }
+ }
+};
+
+/**
+ * Defines a property getter for obj[key].
+ */
+utils.defineGetter = utils.defineGetterSetter;
+
+utils.arrayIndexOf = function(a, item) {
+ if (a.indexOf) {
+ return a.indexOf(item);
+ }
+ var len = a.length;
+ for (var i = 0; i < len; ++i) {
+ if (a[i] == item) {
+ return i;
+ }
+ }
+ return -1;
+};
+
+/**
+ * Returns whether the item was found in the array.
+ */
+utils.arrayRemove = function(a, item) {
+ var index = utils.arrayIndexOf(a, item);
+ if (index != -1) {
+ a.splice(index, 1);
+ }
+ return index != -1;
+};
+
+utils.typeName = function(val) {
+ return Object.prototype.toString.call(val).slice(8, -1);
+};
+
+/**
+ * Returns an indication of whether the argument is an array or not
+ */
+utils.isArray = function(a) {
+ return utils.typeName(a) == 'Array';
+};
+
+/**
+ * Returns an indication of whether the argument is a Date or not
+ */
+utils.isDate = function(d) {
+ return utils.typeName(d) == 'Date';
+};
+
+/**
+ * Does a deep clone of the object.
+ */
+utils.clone = function(obj) {
+ if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {
+ return obj;
+ }
+
+ var retVal, i;
+
+ if(utils.isArray(obj)){
+ retVal = [];
+ for(i = 0; i < obj.length; ++i){
+ retVal.push(utils.clone(obj[i]));
+ }
+ return retVal;
+ }
+
+ retVal = {};
+ for(i in obj){
+ if(!(i in retVal) || retVal[i] != obj[i]) {
+ retVal[i] = utils.clone(obj[i]);
+ }
+ }
+ return retVal;
+};
+
+/**
+ * Returns a wrapped version of the function
+ */
+utils.close = function(context, func, params) {
+ if (typeof params == 'undefined') {
+ return function() {
+ return func.apply(context, arguments);
+ };
+ } else {
+ return function() {
+ return func.apply(context, params);
+ };
+ }
+};
+
+/**
+ * Create a UUID
+ */
+utils.createUUID = function() {
+ return UUIDcreatePart(4) + '-' +
+ UUIDcreatePart(2) + '-' +
+ UUIDcreatePart(2) + '-' +
+ UUIDcreatePart(2) + '-' +
+ UUIDcreatePart(6);
+};
+
+/**
+ * Extends a child object from a parent object using classical inheritance
+ * pattern.
+ */
+utils.extend = (function() {
+ // proxy used to establish prototype chain
+ var F = function() {};
+ // extend Child from Parent
+ return function(Child, Parent) {
+ F.prototype = Parent.prototype;
+ Child.prototype = new F();
+ Child.__super__ = Parent.prototype;
+ Child.prototype.constructor = Child;
+ };
+}());
+
+/**
+ * Alerts a message in any available way: alert or console.log.
+ */
+utils.alert = function(msg) {
+ if (window.alert) {
+ window.alert(msg);
+ } else if (console && console.log) {
+ console.log(msg);
+ }
+};
+
+/**
+ * Formats a string and arguments following it ala sprintf()
+ *
+ * see utils.vformat() for more information
+ */
+utils.format = function(formatString /* ,... */) {
+ var args = [].slice.call(arguments, 1);
+ return utils.vformat(formatString, args);
+};
+
+/**
+ * Formats a string and arguments following it ala vsprintf()
+ *
+ * format chars:
+ * %j - format arg as JSON
+ * %o - format arg as JSON
+ * %c - format arg as ''
+ * %% - replace with '%'
+ * any other char following % will format it's
+ * arg via toString().
+ *
+ * for rationale, see FireBug's Console API:
+ * http://getfirebug.com/wiki/index.php/Console_API
+ */
+utils.vformat = function(formatString, args) {
+ if (formatString === null || formatString === undefined) return "";
+ if (arguments.length == 1) return formatString.toString();
+ if (typeof formatString != "string") return formatString.toString();
+
+ var pattern = /(.*?)%(.)(.*)/;
+ var rest = formatString;
+ var result = [];
+
+ while (args.length) {
+ var arg = args.shift();
+ var match = pattern.exec(rest);
+
+ if (!match) break;
+
+ rest = match[3];
+
+ result.push(match[1]);
+
+ if (match[2] == '%') {
+ result.push('%');
+ args.unshift(arg);
+ continue;
+ }
+
+ result.push(formatted(arg, match[2]));
+ }
+
+ result.push(rest);
+
+ return result.join('');
+};
+
+//------------------------------------------------------------------------------
+function UUIDcreatePart(length) {
+ var uuidpart = "";
+ for (var i=0; i<length; i++) {
+ var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
+ if (uuidchar.length == 1) {
+ uuidchar = "0" + uuidchar;
+ }
+ uuidpart += uuidchar;
+ }
+ return uuidpart;
+}
+
+//------------------------------------------------------------------------------
+function formatted(object, formatChar) {
+
+ try {
+ switch(formatChar) {
+ case 'j':
+ case 'o': return JSON.stringify(object);
+ case 'c': return '';
+ }
+ }
+ catch (e) {
+ return "error JSON.stringify()ing argument: " + e;
+ }
+
+ if ((object === null) || (object === undefined)) {
+ return Object.prototype.toString.call(object);
+ }
+
+ return object.toString();
+}
+
+});
+
+
+window.cordova = require('cordova');
+
+// file: lib/scripts/bootstrap.js
+
+(function (context) {
+ // Replace navigator before any modules are required(), to ensure it happens as soon as possible.
+ // We replace it so that properties that can't be clobbered can instead be overridden.
+ if (context.navigator) {
+ var CordovaNavigator = function() {};
+ CordovaNavigator.prototype = context.navigator;
+ context.navigator = new CordovaNavigator();
+ }
+
+ var channel = require("cordova/channel"),
+ _self = {
+ boot: function () {
+ /**
+ * Create all cordova objects once page has fully loaded and native side is ready.
+ */
+ channel.join(function() {
+ var builder = require('cordova/builder'),
+ platform = require('cordova/platform');
+
+ builder.buildIntoButDoNotClobber(platform.defaults, context);
+ builder.buildIntoAndClobber(platform.clobbers, context);
+ builder.buildIntoAndMerge(platform.merges, context);
+
+ // Call the platform-specific initialization
+ platform.initialize();
+
+ // Fire event to notify that all objects are created
+ channel.onCordovaReady.fire();
+
+ // Fire onDeviceReady event once all constructors have run and
+ // cordova info has been received from native side.
+ channel.join(function() {
+ require('cordova').fireDocumentEvent('deviceready');
+ }, channel.deviceReadyChannelsArray);
+
+ }, [ channel.onDOMContentLoaded, channel.onNativeReady ]);
+ }
+ };
+
+ // boot up once native side is ready
+ channel.onNativeReady.subscribe(_self.boot);
+
+ // _nativeReady is global variable that the native side can set
+ // to signify that the native code is ready. It is a global since
+ // it may be called before any cordova JS is ready.
+ if (window._nativeReady) {
+ channel.onNativeReady.fire();
+ }
+
+}(window));
+
+
+})(); \ No newline at end of file