Skip to content
Browse files

first commit.

  • Loading branch information...
0 parents commit 2da80581cb3b18674971bf2d34b1494b88e34fa2 @kishikawakatsumi committed
Showing with 3,840 additions and 0 deletions.
  1. +10 −0 .gitignore
  2. +50 −0 Classes/JSON.h
  3. +19 −0 Classes/MapDirectionsAppDelegate.h
  4. +43 −0 Classes/MapDirectionsAppDelegate.m
  5. +28 −0 Classes/MapDirectionsViewController.h
  6. +117 −0 Classes/MapDirectionsViewController.m
  7. +68 −0 Classes/NSObject+SBJSON.h
  8. +53 −0 Classes/NSObject+SBJSON.m
  9. +58 −0 Classes/NSString+SBJSON.h
  10. +55 −0 Classes/NSString+SBJSON.m
  11. +15 −0 Classes/RootViewController.h
  12. +213 −0 Classes/RootViewController.m
  13. +75 −0 Classes/SBJSON.h
  14. +212 −0 Classes/SBJSON.m
  15. +86 −0 Classes/SBJsonBase.h
  16. +78 −0 Classes/SBJsonBase.m
  17. +87 −0 Classes/SBJsonParser.h
  18. +475 −0 Classes/SBJsonParser.m
  19. +129 −0 Classes/SBJsonWriter.h
  20. +228 −0 Classes/SBJsonWriter.m
  21. +52 −0 Classes/UICGDirections.h
  22. +117 −0 Classes/UICGDirections.m
  23. +25 −0 Classes/UICGDirectionsOptions.h
  24. +13 −0 Classes/UICGDirectionsOptions.m
  25. +29 −0 Classes/UICGPolyline.h
  26. +54 −0 Classes/UICGPolyline.m
  27. +24 −0 Classes/UICGRoute.h
  28. +45 −0 Classes/UICGRoute.m
  29. +30 −0 Classes/UICGStep.h
  30. +52 −0 Classes/UICGStep.m
  31. +22 −0 Classes/UICGoogleMapsAPI.h
  32. +48 −0 Classes/UICGoogleMapsAPI.m
  33. +31 −0 Classes/UICRouteAnnotation.h
  34. +34 −0 Classes/UICRouteAnnotation.m
  35. +23 −0 Classes/UICRouteOverlayMapView.h
  36. +102 −0 Classes/UICRouteOverlayMapView.m
  37. +282 −0 MainWindow.xib
  38. +30 −0 MapDirections-Info.plist
  39. +382 −0 MapDirections.xcodeproj/project.pbxproj
  40. +14 −0 MapDirections_Prefix.pch
  41. +202 −0 RootViewController.xib
  42. +113 −0 api.html
  43. +17 −0 main.m
10 .gitignore
@@ -0,0 +1,10 @@
+build
+.DS_Store
+*.o
+*.ob
+*.pbxuser
+*.tmproj
+*.mode1*
+*.build
+*~.nib
+
50 Classes/JSON.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2009 Stig Brautaset. 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 author 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.
+ */
+
+/**
+ @mainpage A strict JSON parser and generator for Objective-C
+
+ JSON (JavaScript Object Notation) is a lightweight data-interchange
+ format. This framework provides two apis for parsing and generating
+ JSON. One standard object-based and a higher level api consisting of
+ categories added to existing Objective-C classes.
+
+ Learn more on the http://code.google.com/p/json-framework project site.
+
+ This framework does its best to be as strict as possible, both in what it
+ accepts and what it generates. For example, it does not support trailing commas
+ in arrays or objects. Nor does it support embedded comments, or
+ anything else not in the JSON specification. This is considered a feature.
+
+*/
+
+#import "SBJSON.h"
+#import "NSObject+SBJSON.h"
+#import "NSString+SBJSON.h"
+
19 Classes/MapDirectionsAppDelegate.h
@@ -0,0 +1,19 @@
+//
+// MapDirectionsAppDelegate.h
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright KISHIKAWA Katsumi 2009. All rights reserved.
+//
+
+@interface MapDirectionsAppDelegate : NSObject <UIApplicationDelegate> {
+
+ UIWindow *window;
+ UINavigationController *navigationController;
+}
+
+@property (nonatomic, retain) IBOutlet UIWindow *window;
+@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
+
+@end
+
43 Classes/MapDirectionsAppDelegate.m
@@ -0,0 +1,43 @@
+//
+// MapDirectionsAppDelegate.m
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright KISHIKAWA Katsumi 2009. All rights reserved.
+//
+
+#import "MapDirectionsAppDelegate.h"
+#import "RootViewController.h"
+
+
+@implementation MapDirectionsAppDelegate
+
+@synthesize window;
+@synthesize navigationController;
+
+#pragma mark -
+#pragma mark Application lifecycle
+
+- (void)applicationDidFinishLaunching:(UIApplication *)application {
+
+ // Override point for customization after app launch
+
+ [window addSubview:[navigationController view]];
+ [window makeKeyAndVisible];
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application {
+ // Save data if appropriate
+}
+
+#pragma mark -
+#pragma mark Memory management
+
+- (void)dealloc {
+ [navigationController release];
+ [window release];
+ [super dealloc];
+}
+
+@end
+
28 Classes/MapDirectionsViewController.h
@@ -0,0 +1,28 @@
+//
+// MapDirectionsViewController.h
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright 2009 KISHIKAWA Katsumi. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <MapKit/MapKit.h>
+#import "UICGDirections.h"
+
+@class UICRouteOverlayMapView;
+
+@interface MapDirectionsViewController : UIViewController<MKMapViewDelegate, UICGDirectionsDelegate> {
+ MKMapView *routeMapView;
+ UICRouteOverlayMapView *routeOverlayView;
+ UICGDirections *diretions;
+ NSString *startPoint;
+ NSString *endPoint;
+}
+
+@property (nonatomic, retain) NSString *startPoint;
+@property (nonatomic, retain) NSString *endPoint;
+
+- (void)update;
+
+@end
117 Classes/MapDirectionsViewController.m
@@ -0,0 +1,117 @@
+//
+// MapDirectionsViewController.m
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright 2009 KISHIKAWA Katsumi. All rights reserved.
+//
+
+#import "MapDirectionsViewController.h"
+#import "UICRouteOverlayMapView.h"
+#import "UICGDirections.h"
+#import "UICRouteAnnotation.h"
+
+@implementation MapDirectionsViewController
+
+@synthesize startPoint;
+@synthesize endPoint;
+
+- (void)dealloc {
+ [routeOverlayView release];
+ [startPoint release];
+ [endPoint release];
+ [super dealloc];
+}
+
+- (void)loadView {
+ UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 416.0f)];
+ self.view = contentView;
+ [contentView release];
+ routeMapView = [[MKMapView alloc] initWithFrame:contentView.frame];
+ routeMapView.delegate = self;
+ [contentView addSubview:routeMapView];
+ [routeMapView release];
+
+ routeOverlayView = [[UICRouteOverlayMapView alloc] initWithMapView:routeMapView];
+
+ diretions = [UICGDirections sharedDirections];
+ diretions.delegate = self;
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+ [super viewWillAppear:animated];
+ [self update];
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+ [super viewDidAppear:animated];
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+}
+
+- (void)update {
+ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
+ [diretions loadWithStartPoint:startPoint endPoint:endPoint options:nil];
+}
+
+- (void)directionsDidFinishInitialize:(UICGDirections *)directions {
+ [self update];
+}
+
+- (void)directionsDidUpdateDirections:(UICGDirections *)directions {
+ UICGPolyline *polyline = [directions polyline];
+ NSArray *routePoints = [polyline routePoints];
+ [routeOverlayView setRoutes:routePoints];
+
+ UICRouteAnnotation *startAnnotation = [[[UICRouteAnnotation alloc] initWithCoordinate:[[routePoints objectAtIndex:0] coordinate]
+ title:startPoint
+ annotationType:UICRouteAnnotationTypeStart] autorelease];
+
+ [routeMapView addAnnotation:startAnnotation];
+
+ UICRouteAnnotation *endAnnotation = [[[UICRouteAnnotation alloc] initWithCoordinate:[[routePoints lastObject] coordinate]
+ title:endPoint
+ annotationType:UICRouteAnnotationTypeEnd] autorelease];
+ [routeMapView addAnnotation:endAnnotation];
+
+ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
+}
+
+- (void)directions:(UICGDirections *)directions didFailWithMessage:(NSString *)message {
+ NSLog(@"%@", message);
+ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
+}
+
+#pragma mark <MKMapViewDelegate> Methods
+
+- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
+ routeOverlayView.hidden = YES;
+}
+
+- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
+ routeOverlayView.hidden = NO;
+ [routeOverlayView setNeedsDisplay];
+}
+
+- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation{
+ static NSString *identifier = @"Annotation";
+ MKPinAnnotationView *pinAnnotation = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
+
+ if(!pinAnnotation) {
+ pinAnnotation = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier] autorelease];
+ }
+
+ pinAnnotation.pinColor = [(UICRouteAnnotation *)annotation annotationType] == UICRouteAnnotationTypeStart ? MKPinAnnotationColorGreen : MKPinAnnotationColorRed;
+ pinAnnotation.enabled = YES;
+ pinAnnotation.canShowCallout = YES;
+
+ return pinAnnotation;
+}
+
+@end
68 Classes/NSObject+SBJSON.h
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2009 Stig Brautaset. 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 author 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+
+/**
+ @brief Adds JSON generation to Foundation classes
+
+ This is a category on NSObject that adds methods for returning JSON representations
+ of standard objects to the objects themselves. This means you can call the
+ -JSONRepresentation method on an NSArray object and it'll do what you want.
+ */
+@interface NSObject (NSObject_SBJSON)
+
+/**
+ @brief Returns a string containing the receiver encoded as a JSON fragment.
+
+ This method is added as a category on NSObject but is only actually
+ supported for the following objects:
+ @li NSDictionary
+ @li NSArray
+ @li NSString
+ @li NSNumber (also used for booleans)
+ @li NSNull
+
+ @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
+ */
+- (NSString *)JSONFragment;
+
+/**
+ @brief Returns a string containing the receiver encoded in JSON.
+
+ This method is added as a category on NSObject but is only actually
+ supported for the following objects:
+ @li NSDictionary
+ @li NSArray
+ */
+- (NSString *)JSONRepresentation;
+
+@end
+
53 Classes/NSObject+SBJSON.m
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2009 Stig Brautaset. 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 author 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.
+ */
+
+#import "NSObject+SBJSON.h"
+#import "SBJsonWriter.h"
+
+@implementation NSObject (NSObject_SBJSON)
+
+- (NSString *)JSONFragment {
+ SBJsonWriter *jsonWriter = [SBJsonWriter new];
+ NSString *json = [jsonWriter stringWithFragment:self];
+ if (json)
+ NSLog(@"-JSONFragment failed. Error trace is: %@", [jsonWriter errorTrace]);
+ [jsonWriter release];
+ return json;
+}
+
+- (NSString *)JSONRepresentation {
+ SBJsonWriter *jsonWriter = [SBJsonWriter new];
+ NSString *json = [jsonWriter stringWithObject:self];
+ if (json)
+ NSLog(@"-JSONRepresentation failed. Error trace is: %@", [jsonWriter errorTrace]);
+ [jsonWriter release];
+ return json;
+}
+
+@end
58 Classes/NSString+SBJSON.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2009 Stig Brautaset. 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 author 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ @brief Adds JSON parsing methods to NSString
+
+This is a category on NSString that adds methods for parsing the target string.
+*/
+@interface NSString (NSString_SBJSON)
+
+
+/**
+ @brief Returns the object represented in the receiver, or nil on error.
+
+ Returns a a scalar object represented by the string's JSON fragment representation.
+
+ @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
+ */
+- (id)JSONFragmentValue;
+
+/**
+ @brief Returns the NSDictionary or NSArray represented by the current string's JSON representation.
+
+ Returns the dictionary or array represented in the receiver, or nil on error.
+
+ Returns the NSDictionary or NSArray represented by the current string's JSON representation.
+ */
+- (id)JSONValue;
+
+@end
55 Classes/NSString+SBJSON.m
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2007-2009 Stig Brautaset. 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 author 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.
+ */
+
+#import "NSString+SBJSON.h"
+#import "SBJsonParser.h"
+
+@implementation NSString (NSString_SBJSON)
+
+- (id)JSONFragmentValue
+{
+ SBJsonParser *jsonParser = [SBJsonParser new];
+ id repr = [jsonParser fragmentWithString:self];
+ if (repr)
+ NSLog(@"-JSONFragmentValue failed. Error trace is: %@", [jsonParser errorTrace]);
+ [jsonParser release];
+ return repr;
+}
+
+- (id)JSONValue
+{
+ SBJsonParser *jsonParser = [SBJsonParser new];
+ id repr = [jsonParser objectWithString:self];
+ if (!repr)
+ NSLog(@"-JSONValue failed. Error trace is: %@", [jsonParser errorTrace]);
+ [jsonParser release];
+ return repr;
+}
+
+@end
15 Classes/RootViewController.h
@@ -0,0 +1,15 @@
+//
+// RootViewController.h
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright KISHIKAWA Katsumi 2009. All rights reserved.
+//
+
+@interface RootViewController : UITableViewController<UITextFieldDelegate> {
+ UITextField *startField;
+ UITextField *endField;
+ UISegmentedControl *travelModeSegment;
+}
+
+@end
213 Classes/RootViewController.m
@@ -0,0 +1,213 @@
+//
+// RootViewController.m
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright KISHIKAWA Katsumi 2009. All rights reserved.
+//
+
+#import "RootViewController.h"
+#import "MapDirectionsViewController.h"
+
+@implementation RootViewController
+
+- (void)dealloc {
+ [super dealloc];
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+ [super viewWillAppear:animated];
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+ [super viewDidAppear:animated];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+ [super viewWillDisappear:animated];
+}
+
+- (void)viewDidDisappear:(BOOL)animated {
+ [super viewDidDisappear:animated];
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+}
+
+- (void)viewDidUnload {
+
+}
+
+- (void)done:(id)sender {
+ if ([startField canResignFirstResponder]) {
+ [startField resignFirstResponder];
+ }
+ if ([endField canResignFirstResponder]) {
+ [endField resignFirstResponder];
+ }
+ [self.navigationItem setRightBarButtonItem:nil animated:YES];
+}
+
+#pragma mark UITextFieldDelegate Methods
+
+- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
+ UIBarButtonItem *doneButton = [[[UIBarButtonItem alloc]
+ initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)] autorelease];
+ [self.navigationItem setRightBarButtonItem:doneButton animated:YES];
+ return YES;
+}
+
+- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
+ [self.navigationItem setRightBarButtonItem:nil animated:YES];
+ return YES;
+}
+
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+ if ([textField resignFirstResponder] && textField == startField) {
+ [endField becomeFirstResponder];
+ }
+ return YES;
+}
+
+#pragma mark Table view methods
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+ return 3;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+ if (section == 0) {
+ return 2;
+ } else if (section == 1) {
+ return 1;
+ } else {
+ return 1;
+ }
+}
+
+- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
+ if (section == 0) {
+ return NSLocalizedString(@"Directions", nil);
+ } else if (section == 1) {
+ return NSLocalizedString(@"Travel Mode", nil);
+ } else {
+ return nil;
+ }
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+ NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d", indexPath.section, indexPath.row];
+
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (cell == nil) {
+ cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
+ }
+
+ if (indexPath.section == 0 && indexPath.row == 0) {
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.accessoryType = UITableViewCellAccessoryNone;
+
+ UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 13.0f, 40.0f, 20.0f)];
+ [cell addSubview:textLabel];
+ [textLabel release];
+ textLabel.text = NSLocalizedString(@"Start:", nil);
+ textLabel.font = [UIFont boldSystemFontOfSize:14.0f];
+ textLabel.textAlignment = UITextAlignmentRight;
+ textLabel.textColor = [UIColor lightGrayColor];
+
+ UITextField *inputField = [[UITextField alloc] initWithFrame:CGRectMake(66.0, 0.0, 236.0, 44.0)];
+ inputField.delegate = self;
+ [cell addSubview:inputField];
+ [inputField release];
+
+ [inputField setBorderStyle:UITextBorderStyleNone];
+ [inputField setAdjustsFontSizeToFitWidth:NO];
+ [inputField setClearButtonMode:UITextFieldViewModeWhileEditing];
+ [inputField setClearsOnBeginEditing:NO];
+ [inputField setPlaceholder:nil];
+ [inputField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
+ [inputField setAutocorrectionType:UITextAutocorrectionTypeNo];
+ [inputField setEnablesReturnKeyAutomatically:YES];
+ [inputField setKeyboardType:UIKeyboardTypeDefault];
+ [inputField setReturnKeyType:UIReturnKeyNext];
+ [inputField setEnablesReturnKeyAutomatically:YES];
+
+ [inputField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
+ [inputField setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
+
+ [inputField setText:[NSString stringWithUTF8String:"新宿西口"]];
+
+ startField = inputField;
+ } else if (indexPath.section == 0 && indexPath.row == 1) {
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.accessoryType = UITableViewCellAccessoryNone;
+
+ UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 13.0f, 40.0f, 20.0f)];
+ [cell addSubview:textLabel];
+ [textLabel release];
+ textLabel.text = NSLocalizedString(@"End:", nil);
+ textLabel.font = [UIFont boldSystemFontOfSize:14.0f];
+ textLabel.textAlignment = UITextAlignmentRight;
+ textLabel.textColor = [UIColor lightGrayColor];
+
+ UITextField *inputField = [[UITextField alloc] initWithFrame:CGRectMake(66.0, 0.0, 236.0, 44.0)];
+ inputField.delegate = self;
+ [cell addSubview:inputField];
+ [inputField release];
+
+ [inputField setBorderStyle:UITextBorderStyleNone];
+ [inputField setAdjustsFontSizeToFitWidth:NO];
+ [inputField setClearButtonMode:UITextFieldViewModeWhileEditing];
+ [inputField setClearsOnBeginEditing:NO];
+ [inputField setPlaceholder:nil];
+ [inputField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
+ [inputField setAutocorrectionType:UITextAutocorrectionTypeNo];
+ [inputField setEnablesReturnKeyAutomatically:YES];
+ [inputField setKeyboardType:UIKeyboardTypeDefault];
+ [inputField setReturnKeyType:UIReturnKeyDone];
+ [inputField setEnablesReturnKeyAutomatically:YES];
+
+ [inputField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
+ [inputField setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
+
+ [inputField setText:[NSString stringWithUTF8String:"東京ディズニーランド"]];
+
+ endField = inputField;
+ } else if (indexPath.section == 1 && indexPath.row == 0) {
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.accessoryType = UITableViewCellAccessoryNone;
+
+ travelModeSegment = [[UISegmentedControl alloc] initWithItems:
+ [NSArray arrayWithObjects:NSLocalizedString(@"Driving", nil),
+ NSLocalizedString(@"Train", nil),
+ NSLocalizedString(@"Walking", nil), nil]];
+ [travelModeSegment setFrame:CGRectMake(9.0f, 0.0f, 302.0f, 45.0f)];
+ [travelModeSegment setSelectedSegmentIndex:0];
+ [cell addSubview:travelModeSegment];
+ [travelModeSegment release];
+ } else {
+ cell.selectionStyle = UITableViewCellSelectionStyleBlue;
+ cell.accessoryType = UITableViewCellAccessoryNone;
+ cell.textLabel.text = NSLocalizedString(@"Search", nil);
+ cell.textLabel.textAlignment = UITextAlignmentCenter;
+ cell.textLabel.textColor = [UIColor blueColor];
+ }
+
+ return cell;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+ MapDirectionsViewController *controller = [[MapDirectionsViewController alloc] init];
+ controller.startPoint = startField.text;
+ controller.endPoint = endField.text;
+ [self.navigationController pushViewController:controller animated:YES];
+ [controller release];
+ [tableView deselectRowAtIndexPath:indexPath animated:YES];
+}
+
+@end
75 Classes/SBJSON.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2007-2009 Stig Brautaset. 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 author 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import "SBJsonParser.h"
+#import "SBJsonWriter.h"
+
+/**
+ @brief Facade for SBJsonWriter/SBJsonParser.
+
+ Requests are forwarded to instances of SBJsonWriter and SBJsonParser.
+ */
+@interface SBJSON : SBJsonBase <SBJsonParser, SBJsonWriter> {
+
+@private
+ SBJsonParser *jsonParser;
+ SBJsonWriter *jsonWriter;
+}
+
+
+/// Return the fragment represented by the given string
+- (id)fragmentWithString:(NSString*)jsonrep
+ error:(NSError**)error;
+
+/// Return the object represented by the given string
+- (id)objectWithString:(NSString*)jsonrep
+ error:(NSError**)error;
+
+/// Parse the string and return the represented object (or scalar)
+- (id)objectWithString:(id)value
+ allowScalar:(BOOL)x
+ error:(NSError**)error;
+
+
+/// Return JSON representation of an array or dictionary
+- (NSString*)stringWithObject:(id)value
+ error:(NSError**)error;
+
+/// Return JSON representation of any legal JSON value
+- (NSString*)stringWithFragment:(id)value
+ error:(NSError**)error;
+
+/// Return JSON representation (or fragment) for the given object
+- (NSString*)stringWithObject:(id)value
+ allowScalar:(BOOL)x
+ error:(NSError**)error;
+
+
+@end
212 Classes/SBJSON.m
@@ -0,0 +1,212 @@
+/*
+ Copyright (C) 2007-2009 Stig Brautaset. 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 author 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.
+ */
+
+#import "SBJSON.h"
+
+@implementation SBJSON
+
+- (id)init {
+ self = [super init];
+ if (self) {
+ jsonWriter = [SBJsonWriter new];
+ jsonParser = [SBJsonParser new];
+ [self setMaxDepth:512];
+
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [jsonWriter release];
+ [jsonParser release];
+ [super dealloc];
+}
+
+#pragma mark Writer
+
+
+- (NSString *)stringWithObject:(id)obj {
+ NSString *repr = [jsonWriter stringWithObject:obj];
+ if (repr)
+ return repr;
+
+ [errorTrace release];
+ errorTrace = [[jsonWriter errorTrace] mutableCopy];
+ return nil;
+}
+
+/**
+ Returns a string containing JSON representation of the passed in value, or nil on error.
+ If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error.
+
+ @param value any instance that can be represented as a JSON fragment
+ @param allowScalar wether to return json fragments for scalar objects
+ @param error used to return an error by reference (pass NULL if this is not desired)
+
+@deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
+ */
+- (NSString*)stringWithObject:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error {
+
+ NSString *json = allowScalar ? [jsonWriter stringWithFragment:value] : [jsonWriter stringWithObject:value];
+ if (json)
+ return json;
+
+ [errorTrace release];
+ errorTrace = [[jsonWriter errorTrace] mutableCopy];
+
+ if (error)
+ *error = [errorTrace lastObject];
+ return nil;
+}
+
+/**
+ Returns a string containing JSON representation of the passed in value, or nil on error.
+ If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error.
+
+ @param value any instance that can be represented as a JSON fragment
+ @param error used to return an error by reference (pass NULL if this is not desired)
+
+ @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
+ */
+- (NSString*)stringWithFragment:(id)value error:(NSError**)error {
+ return [self stringWithObject:value
+ allowScalar:YES
+ error:error];
+}
+
+/**
+ Returns a string containing JSON representation of the passed in value, or nil on error.
+ If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error.
+
+ @param value a NSDictionary or NSArray instance
+ @param error used to return an error by reference (pass NULL if this is not desired)
+ */
+- (NSString*)stringWithObject:(id)value error:(NSError**)error {
+ return [self stringWithObject:value
+ allowScalar:NO
+ error:error];
+}
+
+#pragma mark Parsing
+
+- (id)objectWithString:(NSString *)repr {
+ id obj = [jsonParser objectWithString:repr];
+ if (obj)
+ return obj;
+
+ [errorTrace release];
+ errorTrace = [[jsonParser errorTrace] mutableCopy];
+
+ return nil;
+}
+
+/**
+ Returns the object represented by the passed-in string or nil on error. The returned object can be
+ a string, number, boolean, null, array or dictionary.
+
+ @param value the json string to parse
+ @param allowScalar whether to return objects for JSON fragments
+ @param error used to return an error by reference (pass NULL if this is not desired)
+
+ @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
+ */
+- (id)objectWithString:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error {
+
+ id obj = allowScalar ? [jsonParser fragmentWithString:value] : [jsonParser objectWithString:value];
+ if (obj)
+ return obj;
+
+ [errorTrace release];
+ errorTrace = [[jsonParser errorTrace] mutableCopy];
+
+ if (error)
+ *error = [errorTrace lastObject];
+ return nil;
+}
+
+/**
+ Returns the object represented by the passed-in string or nil on error. The returned object can be
+ a string, number, boolean, null, array or dictionary.
+
+ @param repr the json string to parse
+ @param error used to return an error by reference (pass NULL if this is not desired)
+
+ @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
+ */
+- (id)fragmentWithString:(NSString*)repr error:(NSError**)error {
+ return [self objectWithString:repr
+ allowScalar:YES
+ error:error];
+}
+
+/**
+ Returns the object represented by the passed-in string or nil on error. The returned object
+ will be either a dictionary or an array.
+
+ @param repr the json string to parse
+ @param error used to return an error by reference (pass NULL if this is not desired)
+ */
+- (id)objectWithString:(NSString*)repr error:(NSError**)error {
+ return [self objectWithString:repr
+ allowScalar:NO
+ error:error];
+}
+
+
+
+#pragma mark Properties - parsing
+
+- (NSUInteger)maxDepth {
+ return jsonParser.maxDepth;
+}
+
+- (void)setMaxDepth:(NSUInteger)d {
+ jsonWriter.maxDepth = jsonParser.maxDepth = d;
+}
+
+
+#pragma mark Properties - writing
+
+- (BOOL)humanReadable {
+ return jsonWriter.humanReadable;
+}
+
+- (void)setHumanReadable:(BOOL)x {
+ jsonWriter.humanReadable = x;
+}
+
+- (BOOL)sortKeys {
+ return jsonWriter.sortKeys;
+}
+
+- (void)setSortKeys:(BOOL)x {
+ jsonWriter.sortKeys = x;
+}
+
+@end
86 Classes/SBJsonBase.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (C) 2009 Stig Brautaset. 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 author 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+extern NSString * SBJSONErrorDomain;
+
+
+enum {
+ EUNSUPPORTED = 1,
+ EPARSENUM,
+ EPARSE,
+ EFRAGMENT,
+ ECTRL,
+ EUNICODE,
+ EDEPTH,
+ EESCAPE,
+ ETRAILCOMMA,
+ ETRAILGARBAGE,
+ EEOF,
+ EINPUT
+};
+
+/**
+ @brief Common base class for parsing & writing.
+
+ This class contains the common error-handling code and option between the parser/writer.
+ */
+@interface SBJsonBase : NSObject {
+ NSMutableArray *errorTrace;
+
+@protected
+ NSUInteger depth, maxDepth;
+}
+
+/**
+ @brief The maximum recursing depth.
+
+ Defaults to 512. If the input is nested deeper than this the input will be deemed to be
+ malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can
+ turn off this security feature by setting the maxDepth value to 0.
+ */
+@property NSUInteger maxDepth;
+
+/**
+ @brief Return an error trace, or nil if there was no errors.
+
+ Note that this method returns the trace of the last method that failed.
+ You need to check the return value of the call you're making to figure out
+ if the call actually failed, before you know call this method.
+ */
+ @property(copy,readonly) NSArray* errorTrace;
+
+/// @internal for use in subclasses to add errors to the stack trace
+- (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str;
+
+/// @internal for use in subclasess to clear the error before a new parsing attempt
+- (void)clearErrorTrace;
+
+@end
78 Classes/SBJsonBase.m
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2009 Stig Brautaset. 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 author 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.
+ */
+
+#import "SBJsonBase.h"
+NSString * SBJSONErrorDomain = @"org.brautaset.JSON.ErrorDomain";
+
+
+@implementation SBJsonBase
+
+@synthesize errorTrace;
+@synthesize maxDepth;
+
+- (id)init {
+ self = [super init];
+ if (self)
+ self.maxDepth = 512;
+ return self;
+}
+
+- (void)dealloc {
+ [errorTrace release];
+ [super dealloc];
+}
+
+- (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str {
+ NSDictionary *userInfo;
+ if (!errorTrace) {
+ errorTrace = [NSMutableArray new];
+ userInfo = [NSDictionary dictionaryWithObject:str forKey:NSLocalizedDescriptionKey];
+
+ } else {
+ userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
+ str, NSLocalizedDescriptionKey,
+ [errorTrace lastObject], NSUnderlyingErrorKey,
+ nil];
+ }
+
+ NSError *error = [NSError errorWithDomain:SBJSONErrorDomain code:code userInfo:userInfo];
+
+ [self willChangeValueForKey:@"errorTrace"];
+ [errorTrace addObject:error];
+ [self didChangeValueForKey:@"errorTrace"];
+}
+
+- (void)clearErrorTrace {
+ [self willChangeValueForKey:@"errorTrace"];
+ [errorTrace release];
+ errorTrace = nil;
+ [self didChangeValueForKey:@"errorTrace"];
+}
+
+@end
87 Classes/SBJsonParser.h
@@ -0,0 +1,87 @@
+/*
+ Copyright (C) 2009 Stig Brautaset. 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 author 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import "SBJsonBase.h"
+
+/**
+ @brief Options for the parser class.
+
+ This exists so the SBJSON facade can implement the options in the parser without having to re-declare them.
+ */
+@protocol SBJsonParser
+
+/**
+ @brief Return the object represented by the given string.
+
+ Returns the object represented by the passed-in string or nil on error. The returned object can be
+ a string, number, boolean, null, array or dictionary.
+
+ @param repr the json string to parse
+ */
+- (id)objectWithString:(NSString *)repr;
+
+@end
+
+
+/**
+ @brief The JSON parser class.
+
+ JSON is mapped to Objective-C types in the following way:
+
+ @li Null -> NSNull
+ @li String -> NSMutableString
+ @li Array -> NSMutableArray
+ @li Object -> NSMutableDictionary
+ @li Boolean -> NSNumber (initialised with -initWithBool:)
+ @li Number -> NSDecimalNumber
+
+ Since Objective-C doesn't have a dedicated class for boolean values, these turns into NSNumber
+ instances. These are initialised with the -initWithBool: method, and
+ round-trip back to JSON properly. (They won't silently suddenly become 0 or 1; they'll be
+ represented as 'true' and 'false' again.)
+
+ JSON numbers turn into NSDecimalNumber instances,
+ as we can thus avoid any loss of precision. (JSON allows ridiculously large numbers.)
+
+ */
+@interface SBJsonParser : SBJsonBase <SBJsonParser> {
+
+@private
+ const char *c;
+}
+
+@end
+
+// don't use - exists for backwards compatibility with 2.1.x only. Will be removed in 2.3.
+@interface SBJsonParser (Private)
+- (id)fragmentWithString:(id)repr;
+@end
+
+
475 Classes/SBJsonParser.m
@@ -0,0 +1,475 @@
+/*
+ Copyright (C) 2009 Stig Brautaset. 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 author 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.
+ */
+
+#import "SBJsonParser.h"
+
+@interface SBJsonParser ()
+
+- (BOOL)scanValue:(NSObject **)o;
+
+- (BOOL)scanRestOfArray:(NSMutableArray **)o;
+- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o;
+- (BOOL)scanRestOfNull:(NSNull **)o;
+- (BOOL)scanRestOfFalse:(NSNumber **)o;
+- (BOOL)scanRestOfTrue:(NSNumber **)o;
+- (BOOL)scanRestOfString:(NSMutableString **)o;
+
+// Cannot manage without looking at the first digit
+- (BOOL)scanNumber:(NSNumber **)o;
+
+- (BOOL)scanHexQuad:(unichar *)x;
+- (BOOL)scanUnicodeChar:(unichar *)x;
+
+- (BOOL)scanIsAtEnd;
+
+@end
+
+#define skipWhitespace(c) while (isspace(*c)) c++
+#define skipDigits(c) while (isdigit(*c)) c++
+
+
+@implementation SBJsonParser
+
+static char ctrl[0x22];
+
++ (void)initialize
+{
+ ctrl[0] = '\"';
+ ctrl[1] = '\\';
+ for (int i = 1; i < 0x20; i++)
+ ctrl[i+1] = i;
+ ctrl[0x21] = 0;
+}
+
+/**
+ @deprecated This exists in order to provide fragment support in older APIs in one more version.
+ It should be removed in the next major version.
+ */
+- (id)fragmentWithString:(id)repr {
+ [self clearErrorTrace];
+
+ if (!repr) {
+ [self addErrorWithCode:EINPUT description:@"Input was 'nil'"];
+ return nil;
+ }
+
+ depth = 0;
+ c = [repr UTF8String];
+
+ id o;
+ if (![self scanValue:&o]) {
+ return nil;
+ }
+
+ // We found some valid JSON. But did it also contain something else?
+ if (![self scanIsAtEnd]) {
+ [self addErrorWithCode:ETRAILGARBAGE description:@"Garbage after JSON"];
+ return nil;
+ }
+
+ NSAssert1(o, @"Should have a valid object from %@", repr);
+ return o;
+}
+
+- (id)objectWithString:(NSString *)repr {
+
+ id o = [self fragmentWithString:repr];
+ if (!o)
+ return nil;
+
+ // Check that the object we've found is a valid JSON container.
+ if (![o isKindOfClass:[NSDictionary class]] && ![o isKindOfClass:[NSArray class]]) {
+ [self addErrorWithCode:EFRAGMENT description:@"Valid fragment, but not JSON"];
+ return nil;
+ }
+
+ return o;
+}
+
+/*
+ In contrast to the public methods, it is an error to omit the error parameter here.
+ */
+- (BOOL)scanValue:(NSObject **)o
+{
+ skipWhitespace(c);
+
+ switch (*c++) {
+ case '{':
+ return [self scanRestOfDictionary:(NSMutableDictionary **)o];
+ break;
+ case '[':
+ return [self scanRestOfArray:(NSMutableArray **)o];
+ break;
+ case '"':
+ return [self scanRestOfString:(NSMutableString **)o];
+ break;
+ case 'f':
+ return [self scanRestOfFalse:(NSNumber **)o];
+ break;
+ case 't':
+ return [self scanRestOfTrue:(NSNumber **)o];
+ break;
+ case 'n':
+ return [self scanRestOfNull:(NSNull **)o];
+ break;
+ case '-':
+ case '0'...'9':
+ c--; // cannot verify number correctly without the first character
+ return [self scanNumber:(NSNumber **)o];
+ break;
+ case '+':
+ [self addErrorWithCode:EPARSENUM description: @"Leading + disallowed in number"];
+ return NO;
+ break;
+ case 0x0:
+ [self addErrorWithCode:EEOF description:@"Unexpected end of string"];
+ return NO;
+ break;
+ default:
+ [self addErrorWithCode:EPARSE description: @"Unrecognised leading character"];
+ return NO;
+ break;
+ }
+
+ NSAssert(0, @"Should never get here");
+ return NO;
+}
+
+- (BOOL)scanRestOfTrue:(NSNumber **)o
+{
+ if (!strncmp(c, "rue", 3)) {
+ c += 3;
+ *o = [NSNumber numberWithBool:YES];
+ return YES;
+ }
+ [self addErrorWithCode:EPARSE description:@"Expected 'true'"];
+ return NO;
+}
+
+- (BOOL)scanRestOfFalse:(NSNumber **)o
+{
+ if (!strncmp(c, "alse", 4)) {
+ c += 4;
+ *o = [NSNumber numberWithBool:NO];
+ return YES;
+ }
+ [self addErrorWithCode:EPARSE description: @"Expected 'false'"];
+ return NO;
+}
+
+- (BOOL)scanRestOfNull:(NSNull **)o {
+ if (!strncmp(c, "ull", 3)) {
+ c += 3;
+ *o = [NSNull null];
+ return YES;
+ }
+ [self addErrorWithCode:EPARSE description: @"Expected 'null'"];
+ return NO;
+}
+
+- (BOOL)scanRestOfArray:(NSMutableArray **)o {
+ if (maxDepth && ++depth > maxDepth) {
+ [self addErrorWithCode:EDEPTH description: @"Nested too deep"];
+ return NO;
+ }
+
+ *o = [NSMutableArray arrayWithCapacity:8];
+
+ for (; *c ;) {
+ id v;
+
+ skipWhitespace(c);
+ if (*c == ']' && c++) {
+ depth--;
+ return YES;
+ }
+
+ if (![self scanValue:&v]) {
+ [self addErrorWithCode:EPARSE description:@"Expected value while parsing array"];
+ return NO;
+ }
+
+ [*o addObject:v];
+
+ skipWhitespace(c);
+ if (*c == ',' && c++) {
+ skipWhitespace(c);
+ if (*c == ']') {
+ [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in array"];
+ return NO;
+ }
+ }
+ }
+
+ [self addErrorWithCode:EEOF description: @"End of input while parsing array"];
+ return NO;
+}
+
+- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o
+{
+ if (maxDepth && ++depth > maxDepth) {
+ [self addErrorWithCode:EDEPTH description: @"Nested too deep"];
+ return NO;
+ }
+
+ *o = [NSMutableDictionary dictionaryWithCapacity:7];
+
+ for (; *c ;) {
+ id k, v;
+
+ skipWhitespace(c);
+ if (*c == '}' && c++) {
+ depth--;
+ return YES;
+ }
+
+ if (!(*c == '\"' && c++ && [self scanRestOfString:&k])) {
+ [self addErrorWithCode:EPARSE description: @"Object key string expected"];
+ return NO;
+ }
+
+ skipWhitespace(c);
+ if (*c != ':') {
+ [self addErrorWithCode:EPARSE description: @"Expected ':' separating key and value"];
+ return NO;
+ }
+
+ c++;
+ if (![self scanValue:&v]) {
+ NSString *string = [NSString stringWithFormat:@"Object value expected for key: %@", k];
+ [self addErrorWithCode:EPARSE description: string];
+ return NO;
+ }
+
+ [*o setObject:v forKey:k];
+
+ skipWhitespace(c);
+ if (*c == ',' && c++) {
+ skipWhitespace(c);
+ if (*c == '}') {
+ [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in object"];
+ return NO;
+ }
+ }
+ }
+
+ [self addErrorWithCode:EEOF description: @"End of input while parsing object"];
+ return NO;
+}
+
+- (BOOL)scanRestOfString:(NSMutableString **)o
+{
+ *o = [NSMutableString stringWithCapacity:16];
+ do {
+ // First see if there's a portion we can grab in one go.
+ // Doing this caused a massive speedup on the long string.
+ size_t len = strcspn(c, ctrl);
+ if (len) {
+ // check for
+ id t = [[NSString alloc] initWithBytesNoCopy:(char*)c
+ length:len
+ encoding:NSUTF8StringEncoding
+ freeWhenDone:NO];
+ if (t) {
+ [*o appendString:t];
+ [t release];
+ c += len;
+ }
+ }
+
+ if (*c == '"') {
+ c++;
+ return YES;
+
+ } else if (*c == '\\') {
+ unichar uc = *++c;
+ switch (uc) {
+ case '\\':
+ case '/':
+ case '"':
+ break;
+
+ case 'b': uc = '\b'; break;
+ case 'n': uc = '\n'; break;
+ case 'r': uc = '\r'; break;
+ case 't': uc = '\t'; break;
+ case 'f': uc = '\f'; break;
+
+ case 'u':
+ c++;
+ if (![self scanUnicodeChar:&uc]) {
+ [self addErrorWithCode:EUNICODE description: @"Broken unicode character"];
+ return NO;
+ }
+ c--; // hack.
+ break;
+ default:
+ [self addErrorWithCode:EESCAPE description: [NSString stringWithFormat:@"Illegal escape sequence '0x%x'", uc]];
+ return NO;
+ break;
+ }
+ CFStringAppendCharacters((CFMutableStringRef)*o, &uc, 1);
+ c++;
+
+ } else if (*c < 0x20) {
+ [self addErrorWithCode:ECTRL description: [NSString stringWithFormat:@"Unescaped control character '0x%x'", *c]];
+ return NO;
+
+ } else {
+ NSLog(@"should not be able to get here");
+ }
+ } while (*c);
+
+ [self addErrorWithCode:EEOF description:@"Unexpected EOF while parsing string"];
+ return NO;
+}
+
+- (BOOL)scanUnicodeChar:(unichar *)x
+{
+ unichar hi, lo;
+
+ if (![self scanHexQuad:&hi]) {
+ [self addErrorWithCode:EUNICODE description: @"Missing hex quad"];
+ return NO;
+ }
+
+ if (hi >= 0xd800) { // high surrogate char?
+ if (hi < 0xdc00) { // yes - expect a low char
+
+ if (!(*c == '\\' && ++c && *c == 'u' && ++c && [self scanHexQuad:&lo])) {
+ [self addErrorWithCode:EUNICODE description: @"Missing low character in surrogate pair"];
+ return NO;
+ }
+
+ if (lo < 0xdc00 || lo >= 0xdfff) {
+ [self addErrorWithCode:EUNICODE description:@"Invalid low surrogate char"];
+ return NO;
+ }
+
+ hi = (hi - 0xd800) * 0x400 + (lo - 0xdc00) + 0x10000;
+
+ } else if (hi < 0xe000) {
+ [self addErrorWithCode:EUNICODE description:@"Invalid high character in surrogate pair"];
+ return NO;
+ }
+ }
+
+ *x = hi;
+ return YES;
+}
+
+- (BOOL)scanHexQuad:(unichar *)x
+{
+ *x = 0;
+ for (int i = 0; i < 4; i++) {
+ unichar uc = *c;
+ c++;
+ int d = (uc >= '0' && uc <= '9')
+ ? uc - '0' : (uc >= 'a' && uc <= 'f')
+ ? (uc - 'a' + 10) : (uc >= 'A' && uc <= 'F')
+ ? (uc - 'A' + 10) : -1;
+ if (d == -1) {
+ [self addErrorWithCode:EUNICODE description:@"Missing hex digit in quad"];
+ return NO;
+ }
+ *x *= 16;
+ *x += d;
+ }
+ return YES;
+}
+
+- (BOOL)scanNumber:(NSNumber **)o
+{
+ const char *ns = c;
+
+ // The logic to test for validity of the number formatting is relicensed
+ // from JSON::XS with permission from its author Marc Lehmann.
+ // (Available at the CPAN: http://search.cpan.org/dist/JSON-XS/ .)
+
+ if ('-' == *c)
+ c++;
+
+ if ('0' == *c && c++) {
+ if (isdigit(*c)) {
+ [self addErrorWithCode:EPARSENUM description: @"Leading 0 disallowed in number"];
+ return NO;
+ }
+
+ } else if (!isdigit(*c) && c != ns) {
+ [self addErrorWithCode:EPARSENUM description: @"No digits after initial minus"];
+ return NO;
+
+ } else {
+ skipDigits(c);
+ }
+
+ // Fractional part
+ if ('.' == *c && c++) {
+
+ if (!isdigit(*c)) {
+ [self addErrorWithCode:EPARSENUM description: @"No digits after decimal point"];
+ return NO;
+ }
+ skipDigits(c);
+ }
+
+ // Exponential part
+ if ('e' == *c || 'E' == *c) {
+ c++;
+
+ if ('-' == *c || '+' == *c)
+ c++;
+
+ if (!isdigit(*c)) {
+ [self addErrorWithCode:EPARSENUM description: @"No digits after exponent"];
+ return NO;
+ }
+ skipDigits(c);
+ }
+
+ id str = [[NSString alloc] initWithBytesNoCopy:(char*)ns
+ length:c - ns
+ encoding:NSUTF8StringEncoding
+ freeWhenDone:NO];
+ [str autorelease];
+ if (str && (*o = [NSDecimalNumber decimalNumberWithString:str]))
+ return YES;
+
+ [self addErrorWithCode:EPARSENUM description: @"Failed creating decimal instance"];
+ return NO;
+}
+
+- (BOOL)scanIsAtEnd
+{
+ skipWhitespace(c);
+ return !*c;
+}
+
+
+@end
129 Classes/SBJsonWriter.h
@@ -0,0 +1,129 @@
+/*
+ Copyright (C) 2009 Stig Brautaset. 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 author 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import "SBJsonBase.h"
+
+/**
+ @brief Options for the writer class.
+
+ This exists so the SBJSON facade can implement the options in the writer without having to re-declare them.
+ */
+@protocol SBJsonWriter
+
+/**
+ @brief Whether we are generating human-readable (multiline) JSON.
+
+ Set whether or not to generate human-readable JSON. The default is NO, which produces
+ JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable
+ JSON with linebreaks after each array value and dictionary key/value pair, indented two
+ spaces per nesting level.
+ */
+@property BOOL humanReadable;
+
+/**
+ @brief Whether or not to sort the dictionary keys in the output.
+
+ If this is set to YES, the dictionary keys in the JSON output will be in sorted order.
+ (This is useful if you need to compare two structures, for example.) The default is NO.
+ */
+@property BOOL sortKeys;
+
+/**
+ @brief Return JSON representation (or fragment) for the given object.
+
+ Returns a string containing JSON representation of the passed in value, or nil on error.
+ If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error.
+
+ @param value any instance that can be represented as a JSON fragment
+
+ */
+- (NSString*)stringWithObject:(id)value;
+
+@end
+
+
+/**
+ @brief The JSON writer class.
+
+ Objective-C types are mapped to JSON types in the following way:
+
+ @li NSNull -> Null
+ @li NSString -> String
+ @li NSArray -> Array
+ @li NSDictionary -> Object
+ @li NSNumber (-initWithBool:) -> Boolean
+ @li NSNumber -> Number
+
+ In JSON the keys of an object must be strings. NSDictionary keys need
+ not be, but attempting to convert an NSDictionary with non-string keys
+ into JSON will throw an exception.
+
+ NSNumber instances created with the +initWithBool: method are
+ converted into the JSON boolean "true" and "false" values, and vice
+ versa. Any other NSNumber instances are converted to a JSON number the
+ way you would expect.
+
+ */
+@interface SBJsonWriter : SBJsonBase <SBJsonWriter> {
+
+@private
+ BOOL sortKeys, humanReadable;
+}
+
+@end
+
+// don't use - exists for backwards compatibility. Will be removed in 2.3.
+@interface SBJsonWriter (Private)
+- (NSString*)stringWithFragment:(id)value;
+@end
+
+/**
+ @brief Allows generation of JSON for otherwise unsupported classes.
+
+ If you have a custom class that you want to create a JSON representation for you can implement
+ this method in your class. It should return a representation of your object defined
+ in terms of objects that can be translated into JSON. For example, a Person
+ object might implement it like this:
+
+ @code
+ - (id)jsonProxyObject {
+ return [NSDictionary dictionaryWithObjectsAndKeys:
+ name, @"name",
+ phone, @"phone",
+ email, @"email",
+ nil];
+ }
+ @endcode
+
+ */
+@interface NSObject (SBProxyForJson)
+- (id)proxyForJson;
+@end
+
228 Classes/SBJsonWriter.m
@@ -0,0 +1,228 @@
+/*
+ Copyright (C) 2009 Stig Brautaset. 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 author 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.
+ */
+
+#import "SBJsonWriter.h"
+
+@interface SBJsonWriter ()
+
+- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json;
+- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json;
+- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json;
+- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json;
+
+- (NSString*)indent;
+
+@end
+
+@implementation SBJsonWriter
+
+@synthesize sortKeys;
+@synthesize humanReadable;
+
+/**
+ @deprecated This exists in order to provide fragment support in older APIs in one more version.
+ It should be removed in the next major version.
+ */
+- (NSString*)stringWithFragment:(id)value {
+ [self clearErrorTrace];
+ depth = 0;
+ NSMutableString *json = [NSMutableString stringWithCapacity:128];
+
+ if ([self appendValue:value into:json])
+ return json;
+
+ return nil;
+}
+
+
+- (NSString*)stringWithObject:(id)value {
+
+ if ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]) {
+ return [self stringWithFragment:value];
+ }
+
+ [self clearErrorTrace];
+ [self addErrorWithCode:EFRAGMENT description:@"Not valid type for JSON"];
+ return nil;
+}
+
+
+- (NSString*)indent {
+ return [@"\n" stringByPaddingToLength:1 + 2 * depth withString:@" " startingAtIndex:0];
+}
+
+- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json {
+ if ([fragment isKindOfClass:[NSDictionary class]]) {
+ if (![self appendDictionary:fragment into:json])
+ return NO;
+
+ } else if ([fragment isKindOfClass:[NSArray class]]) {
+ if (![self appendArray:fragment into:json])
+ return NO;
+
+ } else if ([fragment isKindOfClass:[NSString class]]) {
+ if (![self appendString:fragment into:json])
+ return NO;
+
+ } else if ([fragment isKindOfClass:[NSNumber class]]) {
+ if ('c' == *[fragment objCType])
+ [json appendString:[fragment boolValue] ? @"true" : @"false"];
+ else
+ [json appendString:[fragment stringValue]];
+
+ } else if ([fragment isKindOfClass:[NSNull class]]) {
+ [json appendString:@"null"];
+ } else if ([fragment respondsToSelector:@selector(proxyForJson)]) {
+ [self appendValue:[fragment proxyForJson] into:json];
+
+ } else {
+ [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"JSON serialisation not supported for %@", [fragment class]]];
+ return NO;
+ }
+ return YES;
+}
+
+- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json {
+ if (maxDepth && ++depth > maxDepth) {
+ [self addErrorWithCode:EDEPTH description: @"Nested too deep"];
+ return NO;
+ }
+ [json appendString:@"["];
+
+ BOOL addComma = NO;
+ for (id value in fragment) {
+ if (addComma)
+ [json appendString:@","];
+ else
+ addComma = YES;
+
+ if ([self humanReadable])
+ [json appendString:[self indent]];
+
+ if (![self appendValue:value into:json]) {
+ return NO;
+ }
+ }
+
+ depth--;
+ if ([self humanReadable] && [fragment count])
+ [json appendString:[self indent]];
+ [json appendString:@"]"];
+ return YES;
+}
+
+- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json {
+ if (maxDepth && ++depth > maxDepth) {
+ [self addErrorWithCode:EDEPTH description: @"Nested too deep"];
+ return NO;
+ }
+ [json appendString:@"{"];
+
+ NSString *colon = [self humanReadable] ? @" : " : @":";
+ BOOL addComma = NO;
+ NSArray *keys = [fragment allKeys];
+ if (self.sortKeys)
+ keys = [keys sortedArrayUsingSelector:@selector(compare:)];
+
+ for (id value in keys) {
+ if (addComma)
+ [json appendString:@","];
+ else
+ addComma = YES;
+
+ if ([self humanReadable])
+ [json appendString:[self indent]];
+
+ if (![value isKindOfClass:[NSString class]]) {
+ [self addErrorWithCode:EUNSUPPORTED description: @"JSON object key must be string"];
+ return NO;
+ }
+
+ if (![self appendString:value into:json])
+ return NO;
+
+ [json appendString:colon];
+ if (![self appendValue:[fragment objectForKey:value] into:json]) {
+ [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"Unsupported value for key %@ in object", value]];
+ return NO;
+ }
+ }
+
+ depth--;
+ if ([self humanReadable] && [fragment count])
+ [json appendString:[self indent]];
+ [json appendString:@"}"];
+ return YES;
+}
+
+- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json {
+
+ static NSMutableCharacterSet *kEscapeChars;
+ if( ! kEscapeChars ) {
+ kEscapeChars = [[NSMutableCharacterSet characterSetWithRange: NSMakeRange(0,32)] retain];
+ [kEscapeChars addCharactersInString: @"\"\\"];
+ }
+
+ [json appendString:@"\""];
+
+ NSRange esc = [fragment rangeOfCharacterFromSet:kEscapeChars];
+ if ( !esc.length ) {
+ // No special chars -- can just add the raw string:
+ [json appendString:fragment];
+
+ } else {
+ NSUInteger length = [fragment length];
+ for (NSUInteger i = 0; i < length; i++) {
+ unichar uc = [fragment characterAtIndex:i];
+ switch (uc) {
+ case '"': [json appendString:@"\\\""]; break;
+ case '\\': [json appendString:@"\\\\"]; break;
+ case '\t': [json appendString:@"\\t"]; break;
+ case '\n': [json appendString:@"\\n"]; break;
+ case '\r': [json appendString:@"\\r"]; break;
+ case '\b': [json appendString:@"\\b"]; break;
+ case '\f': [json appendString:@"\\f"]; break;
+ default:
+ if (uc < 0x20) {
+ [json appendFormat:@"\\u%04x", uc];
+ } else {
+ CFStringAppendCharacters((CFMutableStringRef)json, &uc, 1);
+ }
+ break;
+
+ }
+ }
+ }
+
+ [json appendString:@"\""];
+ return YES;
+}
+
+
+@end
52 Classes/UICGDirections.h
@@ -0,0 +1,52 @@
+//
+// UICGDirections.h
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright 2009 KISHIKAWA Katsumi. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "UICGDirectionsOptions.h"
+#import "UICGRoute.h"
+#import "UICGPolyline.h"
+#import "UICGoogleMapsAPI.h"
+
+@class UICGDirections;
+
+@protocol UICGDirectionsDelegate<NSObject>
+@optional
+- (void)directionsDidFinishInitialize:(UICGDirections *)directions;
+- (void)directionsDidUpdateDirections:(UICGDirections *)directions;
+- (void)directions:(UICGDirections *)directions didFailWithMessage:(NSString *)message;
+@end
+
+@interface UICGDirections : NSObject<UIWebViewDelegate> {
+ id<UICGDirectionsDelegate> delegate;
+ UICGoogleMapsAPI *googleMapsAPI;
+ UICGPolyline *polyline;
+ NSDictionary *distance;
+ NSDictionary *duration;
+}
+
+@property (nonatomic, assign) id<UICGDirectionsDelegate> delegate;
+@property (nonatomic, retain) UICGPolyline *polyline;
+@property (nonatomic, retain) NSDictionary *distance;
+@property (nonatomic, retain) NSDictionary *duration;
+
++ (UICGDirections *)sharedDirections;
+- (id)init;
+- (void)loadWithQuery:(NSString *)query options:(UICGDirectionsOptions *)options;
+- (void)loadWithStartPoint:(NSString *)startPoint endPoint:(NSString *)endPoint options:(UICGDirectionsOptions *)options;
+- (void)loadFromWaypoints:(NSArray *)waypoints options:(UICGDirectionsOptions *)options;
+- (void)clear;
+- (NSDictionary *)status;
+- (NSInteger)numberOfRoutes;
+- (UICGRoute *)routeAtIndex:(NSInteger)index;
+- (NSInteger)numberOfGeocodes;
+- (NSDictionary *)geocodeAtIndex:(NSInteger)index;
+- (NSDictionary *)distance;
+- (NSDictionary *)duration;
+- (UICGPolyline *)polyline;
+
+@end
117 Classes/UICGDirections.m
@@ -0,0 +1,117 @@
+//
+// UICGDirections.m
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright 2009 KISHIKAWA Katsumi. All rights reserved.
+//
+
+#import "UICGDirections.h"
+#import "JSON.h"
+
+static UICGDirections *sharedDirections;
+
+@implementation UICGDirections
+
+@synthesize delegate;
+@synthesize polyline;
+@synthesize distance;
+@synthesize duration;
+
++ (UICGDirections *)sharedDirections {
+ if (!sharedDirections) {
+ sharedDirections = [[UICGDirections alloc] init];
+ }
+ return sharedDirections;
+}
+
+- (id)init {
+ self = [super init];
+ if (self != nil) {
+ googleMapsAPI = [[UICGoogleMapsAPI alloc] init];
+ googleMapsAPI.delegate =self;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [googleMapsAPI release];
+ [super dealloc];
+}
+
+- (void)goolgeMapsAPI:(UICGoogleMapsAPI *)goolgeMapsAPI didGetObject:(NSObject *)object {
+ NSDictionary *dictionary = (NSDictionary *)object;
+ self.polyline = [UICGPolyline polylineWithDictionary:[dictionary objectForKey:@"polyline"]];
+ self.distance = [dictionary objectForKey:@"distance"];
+ self.duration = [dictionary objectForKey:@"duration"];
+
+
+ if ([self.delegate respondsToSelector:@selector(directionsDidUpdateDirections:)]) {
+ [self.delegate directionsDidUpdateDirections:self];
+ }
+}
+
+- (void)goolgeMapsAPI:(UICGoogleMapsAPI *)goolgeMapsAPI didFailWithMessage:(NSString *)message {
+ if ([self.delegate respondsToSelector:@selector(directions:didFailWithMessage:)]) {
+ [self.delegate directions:self didFailWithMessage:message];
+ }
+}
+
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+ NSLog(@"UICGDirections/webViewDidFinishLoad:");
+ if ([self.delegate respondsToSelector:@selector(directionsDidFinishInitialize:)]) {
+ [self.delegate directionsDidFinishInitialize:self];
+ }
+}
+
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
+ NSLog(@"UICGDirections/webView:didFailLoadWithError:");
+}
+
+- (void)loadWithQuery:(NSString *)query options:(UICGDirectionsOptions *)options {
+ [googleMapsAPI stringByEvaluatingJavaScriptFromString:
+ [NSString stringWithFormat:@"loadDirections(%@, %@)", query, [options JSONRepresentation]]];
+}
+
+- (void)loadWithStartPoint:(NSString *)startPoint endPoint:(NSString *)endPoint options:(UICGDirectionsOptions *)options {
+ [googleMapsAPI stringByEvaluatingJavaScriptFromString:
+ [NSString stringWithFormat:@"loadDirections('%@', '%@', 'ja_JP')", startPoint, endPoint, [options JSONRepresentation]]];
+}
+
+- (void)loadFromWaypoints:(NSArray *)waypoints options:(UICGDirectionsOptions *)options {
+
+}
+
+- (void)clear {
+
+}
+
+- (NSDictionary *)status {
+ return nil;
+}
+
+- (NSInteger)numberOfRoutes {
+ return 0;
+}
+
+- (UICGRoute *)routeAtIndex:(NSInteger)index {
+ return nil;
+}
+
+- (NSInteger)numberOfGeocodes {
+ return 0;
+}
+
+- (NSDictionary *)geocodeAtIndex:(NSInteger)index {
+ return nil;
+}
+
+- (NSDictionary *)distance {
+ return nil;
+}
+
+- (NSDictionary *)duration {
+ return nil;
+}
+
+@end
25 Classes/UICGDirectionsOptions.h
@@ -0,0 +1,25 @@
+//
+// UICGDirectionsOptions.h
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright 2009 KISHIKAWA Katsumi. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+typedef enum UICGTravelModes {
+ G_TRAVEL_MODE_DRIVING,
+ G_TRAVEL_MODE_WALKING
+} UICGTravelModes;
+
+@interface UICGDirectionsOptions : NSObject {
+ NSLocale *locale;
+ UICGTravelModes travelMode;
+ BOOL avoidHighways;
+ BOOL getPolyline;
+ BOOL getSteps;
+ BOOL preserveViewport;
+}
+
+@end
13 Classes/UICGDirectionsOptions.m
@@ -0,0 +1,13 @@
+//
+// UICGDirectionsOptions.m
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright 2009 KISHIKAWA Katsumi. All rights reserved.
+//
+
+#import "UICGDirectionsOptions.h"
+
+@implementation UICGDirectionsOptions
+
+@end
29 Classes/UICGPolyline.h
@@ -0,0 +1,29 @@
+//
+// UICGPolyline.h
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright 2009 KISHIKAWA Katsumi. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <CoreLocation/CoreLocation.h>
+
+@interface UICGPolyline : NSObject {
+ NSDictionary *dictionary;
+ NSArray *vertices;
+ NSMutableArray *routePoints;
+ NSInteger vertexCount;
+ NSInteger length;
+}
+
+@property (nonatomic, readonly) NSMutableArray *routePoints;
+@property (nonatomic, readonly) NSInteger vertexCount;
+@property (nonatomic, readonly) NSInteger length;
+
++ (UICGPolyline *)polylineWithDictionary:(NSDictionary *)dic;
+- (id)initWithDictionary:(NSDictionary *)dic;
+- (CLLocation *)vertexAtIndex:(NSInteger)index;
+- (void)insertVertexAtIndex:(NSInteger)index inLocation:(CLLocation *)location;
+
+@end
54 Classes/UICGPolyline.m
@@ -0,0 +1,54 @@
+//
+// UICGPolyline.m
+// MapDirections
+//
+// Created by KISHIKAWA Katsumi on 09/08/10.
+// Copyright 2009 KISHIKAWA Katsumi. All rights reserved.
+//
+
+#import "UICGPolyline.h"
+
+@implementation UICGPolyline
+
+@synthesize routePoints;
+@synthesize vertexCount;