Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Import into GitHub

  • Loading branch information...
commit b8c347737165210564f5ef96aac1ced3f58eaf23 0 parents
@rickfillion rickfillion authored
22 AppController.h
@@ -0,0 +1,22 @@
+//
+// AppController.h
+// ServerSwitchboard
+//
+// Created by Rick Fillion on 23/07/09.
+// All code is provided under the New BSD license.
+//
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface AppController : NSObject {
+ NSArray *companies;
+ BOOL updating;
+}
+
+@property (nonatomic, copy) NSArray *companies;
+@property (nonatomic, assign) BOOL updating;
+
+- (IBAction)update:(id)sender;
+
+@end
40 AppController.m
@@ -0,0 +1,40 @@
+//
+// AppController.m
+// ServerSwitchboard
+//
+// Created by Rick Fillion on 23/07/09.
+// All code is provided under the New BSD license.
+//
+
+#import "AppController.h"
+#import "ServerSwitchboard.h"
+
+@implementation AppController
+
+@synthesize companies;
+@synthesize updating;
+
+- (void)awakeFromNib
+{
+ [self update: self];
+}
+
+- (void)updateCompanies:(NSDictionary *)returnData error:(NSError *)error
+{
+ self.updating = NO;
+ if (error)
+ {
+ // handle the error
+ return;
+ }
+ self.companies = [returnData valueForKey:@"companies"];
+}
+
+- (IBAction)update:(id)sender
+{
+ self.updating = YES;
+ self.companies = [NSArray array];
+ [[ServerSwitchboard switchboard] companiesWithTarget:self selector:@selector(updateCompanies:error:)];
+}
+
+@end
BIN  English.lproj/InfoPlist.strings
Binary file not shown
3,626 English.lproj/MainMenu.xib
3,626 additions, 0 deletions not shown
28 Info.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
44 JSON.h
@@ -0,0 +1,44 @@
+/*
+Copyright (c) 2007, 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.
+*/
+
+#import "SBJSON.h"
+#import "NSObject+SBJSON.h"
+#import "NSString+SBJSON.h"
+
17 License.rtf
@@ -0,0 +1,17 @@
+{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf460
+{\fonttbl\f0\fnil\fcharset0 Verdana;}
+{\colortbl;\red255\green255\blue255;\red14\green14\blue14;}
+{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid0\'02\'05.;}{\levelnumbers\'01;}}{\listname ;}\listid1}}
+{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}}
+\vieww9000\viewh8400\viewkind0
+\deftab720
+\pard\pardeftab720\sl400\sa280\ql\qnatural
+
+\f0\fs24 \cf2 Copyright (c) 2009, Centrix.ca\uc0\u8232 All rights reserved.\
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sl400\sa20\ql\qnatural
+\ls1\ilvl0\cf2 {\listtext \'95 }Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\
+{\listtext \'95 }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.\
+{\listtext \'95 }Neither the name of Centrix.ca nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\
+\pard\pardeftab720\sl400\sa280\ql\qnatural
+\cf2 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.}
60 NSObject+SBJSON.h
@@ -0,0 +1,60 @@
+/*
+Copyright (C) 2007 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>
+
+
+/// Adds JSON generation to NSObject subclasses
+@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
+ */
+- (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
+
57 NSObject+SBJSON.m
@@ -0,0 +1,57 @@
+/*
+Copyright (C) 2007 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 "SBJSON.h"
+
+@implementation NSObject (NSObject_SBJSON)
+
+- (NSString *)JSONFragment {
+ SBJSON *generator = [[SBJSON new] autorelease];
+
+ NSError *error;
+ NSString *json = [generator stringWithFragment:self error:&error];
+
+ if (!json)
+ NSLog(@"%@", error);
+ return json;
+}
+
+- (NSString *)JSONRepresentation {
+ SBJSON *generator = [[SBJSON new] autorelease];
+
+ NSError *error;
+ NSString *json = [generator stringWithObject:self error:&error];
+
+ if (!json)
+ NSLog(@"%@", error);
+ return json;
+}
+
+@end
41 NSString+SBJSON.h
@@ -0,0 +1,41 @@
+/*
+Copyright (C) 2007 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>
+
+/// Adds JSON parsing to NSString
+@interface NSString (NSString_SBJSON)
+
+/// Returns the object represented in the receiver, or nil on error.
+- (id)JSONFragmentValue;
+
+/// Returns the dictionary or array represented in the receiver, or nil on error.
+- (id)JSONValue;
+
+@end
60 NSString+SBJSON.m
@@ -0,0 +1,60 @@
+/*
+Copyright (C) 2007 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 "SBJSON.h"
+
+
+@implementation NSString (NSString_SBJSON)
+
+- (id)JSONFragmentValue
+{
+ SBJSON *json = [[SBJSON new] autorelease];
+
+ NSError *error;
+ id o = [json fragmentWithString:self error:&error];
+
+ if (!o)
+ NSLog(@"%@", error);
+ return o;
+}
+
+- (id)JSONValue
+{
+ SBJSON *json = [[SBJSON new] autorelease];
+
+ NSError *error;
+ id o = [json objectWithString:self error:&error];
+
+ if (!o)
+ NSLog(@"%@", error);
+ return o;
+}
+
+@end
5 README
@@ -0,0 +1,5 @@
+CRServerSwitchboard lets you easily make asynchronous, threadless HTTP calls to your server for JSON encoded data. You can specify which HTTP method to use and optionally pass request data, and the request and response data is automatically converted into JSON notation.
+
+To use it, just provide ServerSwitchboard with some methods that let it know the details of your requests and use those methods in your code.
+
+CRServerSwitchboard can be (and is!) used on both Mac OS X as well as iPhone OS.
137 SBJSON.h
@@ -0,0 +1,137 @@
+/*
+Copyright (C) 2008 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 A strict JSON parser and generator
+
+This is the parser and generator underlying the categories added to
+NSString and various other objects.
+
+Objective-C types are mapped to JSON types and back in the following way:
+
+@li NSNull -> Null -> NSNull
+@li NSString -> String -> NSMutableString
+@li NSArray -> Array -> NSMutableArray
+@li NSDictionary -> Object -> NSMutableDictionary
+@li NSNumber (-initWithBool:) -> Boolean -> NSNumber -initWithBool:
+@li NSNumber -> Number -> NSDecimalNumber
+
+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 +numberWithBool: 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. JSON numbers turn into NSDecimalNumber instances,
+as we can thus avoid any loss of precision.
+
+Strictly speaking correctly formed JSON text must have <strong>exactly
+one top-level container</strong>. (Either an Array or an Object.) Scalars,
+i.e. nulls, numbers, booleans and strings, are not valid JSON on their own.
+It can be quite convenient to pretend that such fragments are valid
+JSON however, and this class lets you do so.
+
+This class does its best to be as strict as possible, both in what it
+accepts and what it generates. (Other than the above mentioned support
+for JSON fragments.) 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.
+
+*/
+@interface SBJSON : NSObject {
+ BOOL humanReadable;
+ BOOL sortKeys;
+ NSUInteger maxDepth;
+
+@private
+ // Used temporarily during scanning/generation
+ NSUInteger depth;
+ const char *c;
+}
+
+/// 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;
+
+/// Whether or not to sort the dictionary keys in the output
+/** The default is to not sort the keys. */
+@property BOOL sortKeys;
+
+/// The maximum depth the parser will go to
+/** Defaults to 512. */
+@property NSUInteger maxDepth;
+
+/// 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 the object represented by the given string
+- (id)objectWithString:(NSString*)jsonrep error:(NSError**)error;
+
+/// Return the fragment represented by the given string
+- (id)fragmentWithString:(NSString*)jsonrep error:(NSError**)error;
+
+/// Return JSON representation (or fragment) for the given object
+- (NSString*)stringWithObject:(id)value
+ allowScalar:(BOOL)x
+ error:(NSError**)error;
+
+/// Parse the string and return the represented object (or scalar)
+- (id)objectWithString:(id)value
+ allowScalar:(BOOL)x
+ error:(NSError**)error;
+
+@end
740 SBJSON.m
@@ -0,0 +1,740 @@
+/*
+Copyright (C) 2008 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"
+
+NSString * SBJSONErrorDomain = @"org.brautaset.JSON.ErrorDomain";
+
+@interface SBJSON (Generator)
+
+- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json error:(NSError**)error;
+- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json error:(NSError**)error;
+- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json error:(NSError**)error;
+- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json error:(NSError**)error;
+
+- (NSString*)indent;
+
+@end
+
+@interface SBJSON (Scanner)
+
+- (BOOL)scanValue:(NSObject **)o error:(NSError **)error;
+
+- (BOOL)scanRestOfArray:(NSMutableArray **)o error:(NSError **)error;
+- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o error:(NSError **)error;
+- (BOOL)scanRestOfNull:(NSNull **)o error:(NSError **)error;
+- (BOOL)scanRestOfFalse:(NSNumber **)o error:(NSError **)error;
+- (BOOL)scanRestOfTrue:(NSNumber **)o error:(NSError **)error;
+- (BOOL)scanRestOfString:(NSMutableString **)o error:(NSError **)error;
+
+// Cannot manage without looking at the first digit
+- (BOOL)scanNumber:(NSNumber **)o error:(NSError **)error;
+
+- (BOOL)scanHexQuad:(unichar *)x error:(NSError **)error;
+- (BOOL)scanUnicodeChar:(unichar *)x error:(NSError **)error;
+
+- (BOOL)scanIsAtEnd;
+
+@end
+
+#pragma mark Private utilities
+
+#define skipWhitespace(c) while (isspace(*c)) c++
+#define skipDigits(c) while (isdigit(*c)) c++
+
+static NSError *err(int code, NSString *str) {
+ NSDictionary *ui = [NSDictionary dictionaryWithObject:str forKey:NSLocalizedDescriptionKey];
+ return [NSError errorWithDomain:SBJSONErrorDomain code:code userInfo:ui];
+}
+
+static NSError *errWithUnderlier(int code, NSError **u, NSString *str) {
+ if (!u)
+ return err(code, str);
+
+ NSDictionary *ui = [NSDictionary dictionaryWithObjectsAndKeys:
+ str, NSLocalizedDescriptionKey,
+ *u, NSUnderlyingErrorKey,
+ nil];
+ return [NSError errorWithDomain:SBJSONErrorDomain code:code userInfo:ui];
+}
+
+
+@implementation SBJSON
+
+static char ctrl[0x22];
+
++ (void)initialize
+{
+ ctrl[0] = '\"';
+ ctrl[1] = '\\';
+ for (int i = 1; i < 0x20; i++)
+ ctrl[i+1] = i;
+ ctrl[0x21] = 0;
+}
+
+- (id)init {
+ if (self = [super init]) {
+ [self setMaxDepth:512];
+ }
+ return self;
+}
+
+#pragma mark Generator
+
+
+/**
+ 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)
+ */
+- (NSString*)stringWithObject:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error {
+ depth = 0;
+ NSMutableString *json = [NSMutableString stringWithCapacity:128];
+
+ NSError *err2 = nil;
+ if (!allowScalar && ![value isKindOfClass:[NSDictionary class]] && ![value isKindOfClass:[NSArray class]]) {
+ err2 = err(EFRAGMENT, @"Not valid type for JSON");
+
+ } else if ([self appendValue:value into:json error:&err2]) {
+ return json;
+ }
+
+ if (error)
+ *error = err2;
+ 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)
+ */
+- (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];
+}
+
+
+- (NSString*)indent {
+ return [@"\n" stringByPaddingToLength:1 + 2 * depth withString:@" " startingAtIndex:0];
+}
+
+- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json error:(NSError**)error {
+ if ([fragment isKindOfClass:[NSDictionary class]]) {
+ if (![self appendDictionary:fragment into:json error:error])
+ return NO;
+
+ } else if ([fragment isKindOfClass:[NSArray class]]) {
+ if (![self appendArray:fragment into:json error:error])
+ return NO;
+
+ } else if ([fragment isKindOfClass:[NSString class]]) {
+ if (![self appendString:fragment into:json error:error])
+ 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 {
+ *error = err(EUNSUPPORTED, [NSString stringWithFormat:@"JSON serialisation not supported for %@", [fragment class]]);
+ return NO;
+ }
+ return YES;
+}
+
+- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json error:(NSError**)error {
+ [json appendString:@"["];
+ depth++;
+
+ 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 error:error]) {
+ return NO;
+ }
+ }
+
+ depth--;
+ if ([self humanReadable] && [fragment count])
+ [json appendString:[self indent]];
+ [json appendString:@"]"];
+ return YES;
+}
+
+- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json error:(NSError**)error {
+ [json appendString:@"{"];
+ depth++;
+
+ 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]]) {
+ *error = err(EUNSUPPORTED, @"JSON object key must be string");
+ return NO;
+ }
+
+ if (![self appendString:value into:json error:error])
+ return NO;
+
+ [json appendString:colon];
+ if (![self appendValue:[fragment objectForKey:value] into:json error:error]) {
+ *error = err(EUNSUPPORTED, [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 error:(NSError**)error {
+
+ 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 {
+ [json appendFormat:@"%C", uc];
+ }
+ break;
+
+ }
+ }
+ }
+
+ [json appendString:@"\""];
+ return YES;
+}
+
+#pragma mark Parser
+
+/**
+ 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 allowScalar whether to return objects for JSON fragments
+ @param error used to return an error by reference (pass NULL if this is not desired)
+ */
+- (id)objectWithString:(id)repr allowScalar:(BOOL)allowScalar error:(NSError**)error {
+
+ if (!repr) {
+ if (error)
+ *error = err(EINPUT, @"Input was 'nil'");
+ return nil;
+ }
+
+ depth = 0;
+ c = [repr UTF8String];
+
+ id o;
+ NSError *err2 = nil;
+ if (![self scanValue:&o error:&err2]) {
+ if (error)
+ *error = err2;
+ return nil;
+ }
+
+ // We found some valid JSON. But did it also contain something else?
+ if (![self scanIsAtEnd]) {
+ if (error)
+ *error = err(ETRAILGARBAGE, @"Garbage after JSON");
+ return nil;
+ }
+
+ // If we don't allow scalars, check that the object we've found is a valid JSON container.
+ if (!allowScalar && ![o isKindOfClass:[NSDictionary class]] && ![o isKindOfClass:[NSArray class]]) {
+ if (error)
+ *error = err(EFRAGMENT, @"Valid fragment, but not JSON");
+ return nil;
+ }
+
+ NSAssert1(o, @"Should have a valid object from %@", repr);
+ return o;
+}
+
+/**
+ 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)
+ */
+- (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];
+}
+
+/*
+ In contrast to the public methods, it is an error to omit the error parameter here.
+ */
+- (BOOL)scanValue:(NSObject **)o error:(NSError **)error
+{
+ skipWhitespace(c);
+
+ switch (*c++) {
+ case '{':
+ return [self scanRestOfDictionary:(NSMutableDictionary **)o error:error];
+ break;
+ case '[':
+ return [self scanRestOfArray:(NSMutableArray **)o error:error];
+ break;
+ case '"':
+ return [self scanRestOfString:(NSMutableString **)o error:error];
+ break;
+ case 'f':
+ return [self scanRestOfFalse:(NSNumber **)o error:error];
+ break;
+ case 't':
+ return [self scanRestOfTrue:(NSNumber **)o error:error];
+ break;
+ case 'n':
+ return [self scanRestOfNull:(NSNull **)o error:error];
+ break;
+ case '-':
+ case '0'...'9':
+ c--; // cannot verify number correctly without the first character
+ return [self scanNumber:(NSNumber **)o error:error];
+ break;
+ case '+':
+ *error = err(EPARSENUM, @"Leading + disallowed in number");
+ return NO;
+ break;
+ case 0x0:
+ *error = err(EEOF, @"Unexpected end of string");
+ return NO;
+ break;
+ default:
+ *error = err(EPARSE, @"Unrecognised leading character");
+ return NO;
+ break;
+ }
+
+ NSAssert(0, @"Should never get here");
+ return NO;
+}
+
+- (BOOL)scanRestOfTrue:(NSNumber **)o error:(NSError **)error
+{
+ if (!strncmp(c, "rue", 3)) {
+ c += 3;
+ *o = [NSNumber numberWithBool:YES];
+ return YES;
+ }
+ *error = err(EPARSE, @"Expected 'true'");
+ return NO;
+}
+
+- (BOOL)scanRestOfFalse:(NSNumber **)o error:(NSError **)error
+{
+ if (!strncmp(c, "alse", 4)) {
+ c += 4;
+ *o = [NSNumber numberWithBool:NO];
+ return YES;
+ }
+ *error = err(EPARSE, @"Expected 'false'");
+ return NO;
+}
+
+- (BOOL)scanRestOfNull:(NSNull **)o error:(NSError **)error
+{
+ if (!strncmp(c, "ull", 3)) {
+ c += 3;
+ *o = [NSNull null];
+ return YES;
+ }
+ *error = err(EPARSE, @"Expected 'null'");
+ return NO;
+}
+
+- (BOOL)scanRestOfArray:(NSMutableArray **)o error:(NSError **)error
+{
+ if (maxDepth && ++depth > maxDepth) {
+ *error = err(EDEPTH, @"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 error:error]) {
+ *error = errWithUnderlier(EPARSE, error, @"Expected value while parsing array");
+ return NO;
+ }
+
+ [*o addObject:v];
+
+ skipWhitespace(c);
+ if (*c == ',' && c++) {
+ skipWhitespace(c);
+ if (*c == ']') {
+ *error = err(ETRAILCOMMA, @"Trailing comma disallowed in array");
+ return NO;
+ }
+ }
+ }
+
+ *error = err(EEOF, @"End of input while parsing array");
+ return NO;
+}
+
+- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o error:(NSError **)error
+{
+ if (maxDepth && ++depth > maxDepth) {
+ *error = err(EDEPTH, @"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 error:error])) {
+ *error = errWithUnderlier(EPARSE, error, @"Object key string expected");
+ return NO;
+ }
+
+ skipWhitespace(c);
+ if (*c != ':') {
+ *error = err(EPARSE, @"Expected ':' separating key and value");
+ return NO;
+ }
+
+ c++;
+ if (![self scanValue:&v error:error]) {
+ NSString *string = [NSString stringWithFormat:@"Object value expected for key: %@", k];
+ *error = errWithUnderlier(EPARSE, error, string);
+ return NO;
+ }
+
+ [*o setObject:v forKey:k];
+
+ skipWhitespace(c);
+ if (*c == ',' && c++) {
+ skipWhitespace(c);
+ if (*c == '}') {
+ *error = err(ETRAILCOMMA, @"Trailing comma disallowed in object");
+ return NO;
+ }
+ }
+ }
+
+ *error = err(EEOF, @"End of input while parsing object");
+ return NO;
+}
+
+- (BOOL)scanRestOfString:(NSMutableString **)o error:(NSError **)error
+{
+ *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 error:error]) {
+ *error = errWithUnderlier(EUNICODE, error, @"Broken unicode character");
+ return NO;
+ }
+ c--; // hack.
+ break;
+ default:
+ *error = err(EESCAPE, [NSString stringWithFormat:@"Illegal escape sequence '0x%x'", uc]);
+ return NO;
+ break;
+ }
+ [*o appendFormat:@"%C", uc];
+ c++;
+
+ } else if (*c < 0x20) {
+ *error = err(ECTRL, [NSString stringWithFormat:@"Unescaped control character '0x%x'", *c]);
+ return NO;
+
+ } else {
+ NSLog(@"should not be able to get here");
+ }
+ } while (*c);
+
+ *error = err(EEOF, @"Unexpected EOF while parsing string");
+ return NO;
+}
+
+- (BOOL)scanUnicodeChar:(unichar *)x error:(NSError **)error
+{
+ unichar hi, lo;
+
+ if (![self scanHexQuad:&hi error:error]) {
+ *error = err(EUNICODE, @"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 error:error])) {
+ *error = errWithUnderlier(EUNICODE, error, @"Missing low character in surrogate pair");
+ return NO;
+ }
+
+ if (lo < 0xdc00 || lo >= 0xdfff) {
+ *error = err(EUNICODE, @"Invalid low surrogate char");
+ return NO;
+ }
+
+ hi = (hi - 0xd800) * 0x400 + (lo - 0xdc00) + 0x10000;
+
+ } else if (hi < 0xe000) {
+ *error = err(EUNICODE, @"Invalid high character in surrogate pair");
+ return NO;
+ }
+ }
+
+ *x = hi;
+ return YES;
+}
+
+- (BOOL)scanHexQuad:(unichar *)x error:(NSError **)error
+{
+ *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) {
+ *error = err(EUNICODE, @"Missing hex digit in quad");
+ return NO;
+ }
+ *x *= 16;
+ *x += d;
+ }
+ return YES;
+}
+
+- (BOOL)scanNumber:(NSNumber **)o error:(NSError **)error
+{
+ 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)) {
+ *error = err(EPARSENUM, @"Leading 0 disallowed in number");
+ return NO;
+ }
+
+ } else if (!isdigit(*c) && c != ns) {
+ *error = err(EPARSENUM, @"No digits after initial minus");
+ return NO;
+
+ } else {
+ skipDigits(c);
+ }
+
+ // Fractional part
+ if ('.' == *c && c++) {
+
+ if (!isdigit(*c)) {
+ *error = err(EPARSENUM, @"No digits after decimal point");
+ return NO;
+ }
+ skipDigits(c);
+ }
+
+ // Exponential part
+ if ('e' == *c || 'E' == *c) {
+ c++;
+
+ if ('-' == *c || '+' == *c)
+ c++;
+
+ if (!isdigit(*c)) {
+ *error = err(EPARSENUM, @"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;
+
+ *error = err(EPARSENUM, @"Failed creating decimal instance");
+ return NO;
+}
+
+- (BOOL)scanIsAtEnd
+{
+ skipWhitespace(c);
+ return !*c;
+}
+
+
+
+#pragma mark Properties
+
+@synthesize humanReadable;
+@synthesize sortKeys;
+@synthesize maxDepth;
+
+@end
28 ServerSwitchboard.h
@@ -0,0 +1,28 @@
+//
+// ServerSwitchboard.h
+// ServerSwitchboard
+//
+// Created by Chris Farber on 30/03/09.
+// All code is provided under the New BSD license.
+//
+
+#import <Cocoa/Cocoa.h>
+
+@interface ServerSwitchboard : NSObject {
+ CFMutableDictionaryRef connections;
+ CFMutableDictionaryRef connectionsData;
+ NSUserDefaults * defaults;
+ NSURL * apiURL;
+}
+
++ (NSString *)baseURL;
++ switchboard;
+
+// these methods are asynchronous and use a callback
+// the callback follows this pattern:
+// - (void) requestFinishedWithData: (NSDictionary *)info error: (NSError *)error
+
+- (void) companiesWithTarget:(id)target selector: (SEL)sel;
+
+
+@end
160 ServerSwitchboard.m
@@ -0,0 +1,160 @@
+//
+// ServerSwitchboard.m
+// Bodega
+//
+// Created by Chris Farber on 30/03/09.
+// All code is provided under the New BSD license.
+//
+
+
+#import "ServerSwitchboard.h"
+#import "JSON.h"
+
+static ServerSwitchboard * sharedSwitchboard = nil;
+
+@interface ServerSwitchboard (Private)
+
+- (void) _sendRequest: (NSString *)verb withData: (NSDictionary *)data forPath: (NSString *)subpath
+ target: (id)target selector: (SEL)sel;
+- (void) _returnResponseForConnection: (NSURLConnection *)connection;
+- (void) connection: (NSURLConnection *)connection didReceiveResponse: (NSHTTPURLResponse *)response;
+- (void) connection: (NSURLConnection *)connection didReceiveData: (NSData *)data;
+- (void) connection: (NSURLConnection *)connection didFailWithError: (NSError *)error;
+- (void) connectionDidFinishLoading: (NSURLConnection *)connection;
+
+@end
+
+@implementation ServerSwitchboard
+
++ (NSString *)baseURL
+{
+ return @"http://centrix.ca/";
+}
+
++ switchboard
+{
+ if (!sharedSwitchboard) [self new];
+ return sharedSwitchboard;
+}
+
+- init
+{
+ [super init];
+ if (sharedSwitchboard) {
+ [self release];
+ return sharedSwitchboard;
+ }
+ connections = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ connectionsData = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ apiURL = [[NSURL alloc] initWithString: [NSString stringWithFormat:@"%@/code/", [ServerSwitchboard baseURL]]];
+ defaults = [NSUserDefaults standardUserDefaults];
+ sharedSwitchboard = self;
+ return self;
+}
+
+- (void)dealloc
+{
+ [defaults release];
+ CFRelease(connections);
+ CFRelease(connectionsData);
+ [apiURL release];
+ [super dealloc];
+}
+
+- (void) companiesWithTarget:(id)target selector: (SEL)sel
+{
+ [self _sendRequest: @"GET"
+ withData: nil
+ forPath: @"sample.json"
+ target: target
+ selector: sel];
+}
+
+
+
+@end
+
+@implementation ServerSwitchboard (Private)
+
+- (void)_sendRequest: (NSString *)verb withData: (NSDictionary *)data forPath: (NSString *)subpath
+ target: (id)target selector: (SEL)sel
+{
+ NSURL * requestURL = [NSURL URLWithString: subpath relativeToURL: apiURL];
+ NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL: requestURL];
+ [request setHTTPMethod: verb];
+ if (data) {
+ [request setValue: @"application/json" forHTTPHeaderField: @"Content-Type"];
+ [request setHTTPBody: [[data JSONRepresentation] dataUsingEncoding: NSUTF8StringEncoding]];
+ //NSLog(@"json rep = %@", [data JSONRepresentation]);
+ }
+ NSURLConnection * connection = [[NSURLConnection alloc]
+ initWithRequest: request delegate: self];
+ if (!connection) {
+ NSError * error = [NSError errorWithDomain: @"ServerSwitchboardError"
+ code: 1
+ userInfo: nil];
+ [target performSelector: sel withObject: nil withObject: error];
+ return;
+ }
+ CFDictionarySetValue(connectionsData, connection, [NSMutableData data]);
+ NSValue * selector = [NSValue value: &sel withObjCType: @encode(SEL)];
+ NSDictionary * targetInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ selector, @"selector",
+ target, @"target",
+ nil];
+ CFDictionarySetValue(connections, connection, targetInfo);
+}
+
+- (void) connection: (NSURLConnection *)connection didReceiveResponse: (NSHTTPURLResponse *)response
+{
+ NSMutableDictionary * targetInfo = (id)CFDictionaryGetValue(connections, connection);
+ [targetInfo setValue: response forKey: @"response"];
+}
+
+- (void) connection: (NSURLConnection *)connection didReceiveData: (NSData *)data
+{
+ NSMutableData * connectionData = (id)CFDictionaryGetValue(connectionsData, connection);
+ [connectionData appendData: data];
+}
+
+- (void) connection: (NSURLConnection *)connection didFailWithError: (NSError *)error
+{
+ NSMutableDictionary * targetInfo = (id)CFDictionaryGetValue(connections, connection);
+ [targetInfo setValue: error forKey: @"error"];
+ [self _returnResponseForConnection: connection];
+}
+
+- (void) connectionDidFinishLoading: (NSURLConnection *)connection
+{
+ [self _returnResponseForConnection: connection];
+}
+
+- (void) _returnResponseForConnection: (NSURLConnection *)connection
+{
+ NSMutableDictionary * targetInfo = (id)CFDictionaryGetValue(connections, connection);
+ NSMutableData * data = (id)CFDictionaryGetValue(connectionsData, connection);
+ id target = [targetInfo valueForKey: @"target"];
+ SEL selector;
+ [[targetInfo valueForKey: @"selector"] getValue: &selector];
+ NSError * error = [targetInfo valueForKey: @"error"];
+ if (!error) {
+ NSHTTPURLResponse * response = [targetInfo valueForKey: @"response"];
+ NSInteger status = [response statusCode];
+ if (status != 200) error = [NSError errorWithDomain: @"APIError" code: status userInfo: nil];
+ }
+ NSDictionary * dataDictionary = nil;
+ if ([data length] && [error code] != 401) {
+ NSString * json = [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];
+ NSLog(@"got response: %@", json);
+ dataDictionary = [json JSONValue];
+ }
+ [target performSelector: selector withObject: dataDictionary withObject: error];
+ CFDictionaryRemoveValue(connections, connection);
+ CFDictionaryRemoveValue(connectionsData, connection);
+ [connection release];
+}
+
+
+@end
BIN  ServerSwitchboard.xcodeproj/TemplateIcon.icns
Binary file not shown
316 ServerSwitchboard.xcodeproj/project.pbxproj
@@ -0,0 +1,316 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; };
+ 5FED982E101946F500B0E215 /* ServerSwitchboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FED982D101946F500B0E215 /* ServerSwitchboard.m */; };
+ 5FED983D10194CB000B0E215 /* NSObject+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FED983810194CB000B0E215 /* NSObject+SBJSON.m */; };
+ 5FED983E10194CB000B0E215 /* NSString+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FED983A10194CB000B0E215 /* NSString+SBJSON.m */; };
+ 5FED983F10194CB000B0E215 /* SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FED983C10194CB000B0E215 /* SBJSON.m */; };
+ 5FED985810194EC200B0E215 /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FED985710194EC200B0E215 /* AppController.m */; };
+ 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
+ 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
+ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
+ 1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
+ 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
+ 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ 32CA4F630368D1EE00C91783 /* ServerSwitchboard_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerSwitchboard_Prefix.pch; sourceTree = "<group>"; };
+ 5FED982C101946F500B0E215 /* ServerSwitchboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerSwitchboard.h; sourceTree = "<group>"; };
+ 5FED982D101946F500B0E215 /* ServerSwitchboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ServerSwitchboard.m; sourceTree = "<group>"; };
+ 5FED983610194CB000B0E215 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = "<group>"; };
+ 5FED983710194CB000B0E215 /* NSObject+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SBJSON.h"; sourceTree = "<group>"; };
+ 5FED983810194CB000B0E215 /* NSObject+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SBJSON.m"; sourceTree = "<group>"; };
+ 5FED983910194CB000B0E215 /* NSString+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SBJSON.h"; sourceTree = "<group>"; };
+ 5FED983A10194CB000B0E215 /* NSString+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SBJSON.m"; sourceTree = "<group>"; };
+ 5FED983B10194CB000B0E215 /* SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJSON.h; sourceTree = "<group>"; };
+ 5FED983C10194CB000B0E215 /* SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJSON.m; sourceTree = "<group>"; };
+ 5FED985610194EC200B0E215 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = "<group>"; };
+ 5FED985710194EC200B0E215 /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppController.m; sourceTree = "<group>"; };
+ 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 8D1107320486CEB800E47090 /* ServerSwitchboard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ServerSwitchboard.app; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8D11072E0486CEB800E47090 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 080E96DDFE201D6D7F000001 /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ 5FED984010194CB400B0E215 /* Third Party */,
+ 5FED982C101946F500B0E215 /* ServerSwitchboard.h */,
+ 5FED982D101946F500B0E215 /* ServerSwitchboard.m */,
+ 5FED985610194EC200B0E215 /* AppController.h */,
+ 5FED985710194EC200B0E215 /* AppController.m */,
+ );
+ name = Classes;
+ sourceTree = "<group>";
+ };
+ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
+ );
+ name = "Linked Frameworks";
+ sourceTree = "<group>";
+ };
+ 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 29B97324FDCFA39411CA2CEA /* AppKit.framework */,
+ 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */,
+ 29B97325FDCFA39411CA2CEA /* Foundation.framework */,
+ );
+ name = "Other Frameworks";
+ sourceTree = "<group>";
+ };
+ 19C28FACFE9D520D11CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D1107320486CEB800E47090 /* ServerSwitchboard.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 29B97314FDCFA39411CA2CEA /* ServerSwitchboard */ = {
+ isa = PBXGroup;
+ children = (
+ 080E96DDFE201D6D7F000001 /* Classes */,
+ 29B97315FDCFA39411CA2CEA /* Other Sources */,
+ 29B97317FDCFA39411CA2CEA /* Resources */,
+ 29B97323FDCFA39411CA2CEA /* Frameworks */,
+ 19C28FACFE9D520D11CA2CBB /* Products */,
+ );
+ name = ServerSwitchboard;
+ sourceTree = "<group>";
+ };
+ 29B97315FDCFA39411CA2CEA /* Other Sources */ = {
+ isa = PBXGroup;
+ children = (
+ 32CA4F630368D1EE00C91783 /* ServerSwitchboard_Prefix.pch */,
+ 29B97316FDCFA39411CA2CEA /* main.m */,
+ );
+ name = "Other Sources";
+ sourceTree = "<group>";
+ };
+ 29B97317FDCFA39411CA2CEA /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 8D1107310486CEB800E47090 /* Info.plist */,
+ 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
+ 1DDD58140DA1D0A300B32029 /* MainMenu.xib */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
+ 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 5FED984010194CB400B0E215 /* Third Party */ = {
+ isa = PBXGroup;
+ children = (
+ 5FED983610194CB000B0E215 /* JSON.h */,
+ 5FED983710194CB000B0E215 /* NSObject+SBJSON.h */,
+ 5FED983810194CB000B0E215 /* NSObject+SBJSON.m */,
+ 5FED983910194CB000B0E215 /* NSString+SBJSON.h */,
+ 5FED983A10194CB000B0E215 /* NSString+SBJSON.m */,
+ 5FED983B10194CB000B0E215 /* SBJSON.h */,
+ 5FED983C10194CB000B0E215 /* SBJSON.m */,
+ );
+ name = "Third Party";
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 8D1107260486CEB800E47090 /* ServerSwitchboard */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "ServerSwitchboard" */;
+ buildPhases = (
+ 8D1107290486CEB800E47090 /* Resources */,
+ 8D11072C0486CEB800E47090 /* Sources */,
+ 8D11072E0486CEB800E47090 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ServerSwitchboard;
+ productInstallPath = "$(HOME)/Applications";
+ productName = ServerSwitchboard;
+ productReference = 8D1107320486CEB800E47090 /* ServerSwitchboard.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 29B97313FDCFA39411CA2CEA /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ServerSwitchboard" */;
+ compatibilityVersion = "Xcode 3.1";
+ hasScannedForEncodings = 1;
+ mainGroup = 29B97314FDCFA39411CA2CEA /* ServerSwitchboard */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8D1107260486CEB800E47090 /* ServerSwitchboard */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D1107290486CEB800E47090 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
+ 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8D11072C0486CEB800E47090 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D11072D0486CEB800E47090 /* main.m in Sources */,
+ 5FED982E101946F500B0E215 /* ServerSwitchboard.m in Sources */,
+ 5FED983D10194CB000B0E215 /* NSObject+SBJSON.m in Sources */,
+ 5FED983E10194CB000B0E215 /* NSString+SBJSON.m in Sources */,
+ 5FED983F10194CB000B0E215 /* SBJSON.m in Sources */,
+ 5FED985810194EC200B0E215 /* AppController.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 089C165DFE840E0CC02AAC07 /* English */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+ 1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 1DDD58150DA1D0A300B32029 /* English */,
+ );
+ name = MainMenu.xib;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ C01FCF4B08A954540054247B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = ServerSwitchboard_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "$(HOME)/Applications";
+ PRODUCT_NAME = ServerSwitchboard;
+ };
+ name = Debug;
+ };
+ C01FCF4C08A954540054247B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = ServerSwitchboard_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "$(HOME)/Applications";
+ PRODUCT_NAME = ServerSwitchboard;
+ };
+ name = Release;
+ };
+ C01FCF4F08A954540054247B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PREBINDING = NO;
+ SDKROOT = macosx10.5;
+ };
+ name = Debug;
+ };
+ C01FCF5008A954540054247B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = macosx10.5;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "ServerSwitchboard" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C01FCF4B08A954540054247B /* Debug */,
+ C01FCF4C08A954540054247B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ServerSwitchboard" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C01FCF4F08A954540054247B /* Debug */,
+ C01FCF5008A954540054247B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
+}
7 ServerSwitchboard_Prefix.pch
@@ -0,0 +1,7 @@
+//
+// Prefix header for all source files of the 'ServerSwitchboard' target in the 'ServerSwitchboard' project
+//
+
+#ifdef __OBJC__
+ #import <Cocoa/Cocoa.h>
+#endif
14 main.m
@@ -0,0 +1,14 @@
+//
+// main.m
+// ServerSwitchboard
+//
+// Created by Rick Fillion on 23/07/09.
+// Copyright Centrix.ca 2009. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+int main(int argc, char *argv[])
+{
+ return NSApplicationMain(argc, (const char **) argv);
+}
16 version.plist
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>BuildVersion</key>
+ <string>3</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>ProductBuildVersion</key>
+ <string>9M2729</string>
+ <key>ProjectName</key>
+ <string>DevToolsWizardTemplates</string>
+ <key>SourceVersion</key>
+ <string>11600000</string>
+</dict>
+</plist>
Please sign in to comment.
Something went wrong with that request. Please try again.