├── English.lproj └── InfoPlist.strings ├── TranslationKit.h ├── TranslationKit_Prefix.pch ├── Tests ├── LogicTests.h └── LogicTests.m ├── Tests-Info.plist ├── Info.plist ├── README.markdown ├── Classes ├── MRTranslationOperation.h └── MRTranslationOperation.m ├── JSON ├── NSString+SBJSON.m ├── NSObject+SBJSON.m ├── JSON.h ├── NSString+SBJSON.h ├── NSObject+SBJSON.h ├── SBJsonBase.m ├── SBJSON.h ├── SBJsonBase.h ├── SBJsonParser.h ├── SBJsonWriter.h ├── SBJSON.m ├── SBJsonWriter.m └── SBJsonParser.m └── TranslationKit.xcodeproj └── project.pbxproj /English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /TranslationKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // TranslationKit.h 3 | // TranslationKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "MRTranslationOperation.h" 9 | -------------------------------------------------------------------------------- /TranslationKit_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'TranslationKit' target in the 'TranslationKit' project. 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /Tests/LogicTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // LogicTests.h 3 | // TranslationKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import 9 | #import 10 | 11 | @interface LogicTests : SenTestCase < MRTranslationOperationDelegate > { 12 | NSOperationQueue *queue; 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.MattRajca.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.MattRajca.${PRODUCT_NAME:rfc1034Identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Tests/LogicTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // LogicTests.m 3 | // TranslationKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "LogicTests.h" 9 | 10 | @implementation LogicTests 11 | 12 | - (void)setUp { 13 | queue = [[NSOperationQueue alloc] init]; 14 | } 15 | 16 | - (void)testTranslation { 17 | MRTranslationOperation *op = [[MRTranslationOperation alloc] initWithSourceString:@"Buenos Dias!" 18 | destinationLanguageCode:@"en"]; 19 | 20 | STAssertNotNil(op, @"Cannot create the operation"); 21 | 22 | op.delegate = self; 23 | 24 | [queue addOperation:op]; 25 | [op release]; 26 | 27 | while ([[queue operations] count]) { 28 | [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.2f]]; 29 | } 30 | } 31 | 32 | - (void)translationOperation:(MRTranslationOperation *)operation 33 | didFinishTranslatingText:(NSString *)result { 34 | 35 | NSLog(@"translation: %@", result); 36 | 37 | STAssertTrue([NSThread isMainThread], @"The delegate methods should be called on the main thread"); 38 | STAssertNotNil(result, @"The translated text is invalid"); 39 | } 40 | 41 | - (void)translationOperation:(MRTranslationOperation *)operation 42 | didFailWithError:(NSError *)error { 43 | 44 | STAssertTrue([NSThread isMainThread], @"The delegate methods should be called on the main thread"); 45 | STFail(@"Failed to translate the source string: %@", error); 46 | } 47 | 48 | - (void)tearDown { 49 | [queue release]; 50 | queue = nil; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | TranslationKit 2 | ============== 3 | 4 | TranslationKit is a simple Cocoa framework which utilizes Google Translate to translate text. 5 | 6 | Usage 7 | ----- 8 | 9 | The framework consists of one class - `MRTranslationOperation` - and as the name suggests, it is a subclass of `NSOperation`. A source string to translate and a destination language code need to be passed to the initializer. A list of language codes that Google Translate supports can be found [here](http://code.google.com/apis/ajaxlanguage/documentation/reference.html#LangNameArray). 10 | 11 | Basic usage: 12 | 13 | MRTranslationOperation *op = [[MRTranslationOperation alloc] initWithSourceString:@"Buenos Dias!" 14 | destinationLanguageCode:@"en"]; 15 | 16 | op.delegate = self; 17 | 18 | [queue addOperation:op]; 19 | [op release]; 20 | 21 | The code above will translate the string "Buenos Dias!" to English. Don't forget to set the delegate to receive a callback with the translated string. 22 | 23 | Some applications may also want to convert a localized display name of a language to its corresponding language code. This can be done using the `NSLocale` class as shown below. 24 | 25 | `[NSLocale canonicalLanguageIdentifierFromString:@"English"]; // this returns "en"` 26 | 27 | The `MRTranslationOperation` class can also be used from within the context of a `NSThread`. This can be done by invoking the `main` method of an instance of `MRTranslationOperation` using `+ [NSThread detachNewThreadSelector:toTarget:withObject:]` 28 | 29 | iPhone 30 | ------ 31 | 32 | To use TranslationKit on iPhone, simply include the MRTranslationOperation.[hm] files with your project. Be sure you also include the required JSON directory. 33 | -------------------------------------------------------------------------------- /Classes/MRTranslationOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // MRTranslationOperation.h 3 | // TranslationKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | /* 11 | 12 | Language codes refer to ISO language codes 13 | 14 | See http://code.google.com/apis/ajaxlanguage/documentation/reference.html#LangNameArray 15 | for a list of supported languages 16 | 17 | To convert the localized name of a language to its corresponding language code use: 18 | 19 | + [NSLocale canonicalLanguageIdentifierFromString:] 20 | 21 | for example calling: 22 | 23 | [NSLocale canonicalLanguageIdentifierFromString:@"English"] 24 | 25 | would return "en" 26 | 27 | */ 28 | 29 | @protocol MRTranslationOperationDelegate; 30 | 31 | @interface MRTranslationOperation : NSOperation { 32 | @private 33 | NSString *sourceString; 34 | NSString *destLanguageCode; 35 | NSString *sourceLanguageCode; 36 | id < MRTranslationOperationDelegate > delegate; 37 | } 38 | 39 | // If not specified, the language of the source string will be detected automatically 40 | @property (nonatomic, copy) NSString *sourceLanguageCode; 41 | 42 | // All delegate methods are called back on the main thread 43 | @property (nonatomic, assign) id < MRTranslationOperationDelegate > delegate; 44 | 45 | /* The source string and destination language code must not be nil */ 46 | - (id)initWithSourceString:(NSString *)source destinationLanguageCode:(NSString *)code; 47 | 48 | @end 49 | 50 | 51 | @protocol MRTranslationOperationDelegate < NSObject > 52 | 53 | - (void)translationOperation:(MRTranslationOperation *)operation didFinishTranslatingText:(NSString *)result; 54 | 55 | @optional 56 | - (void)translationOperation:(MRTranslationOperation *)operation didFailWithError:(NSError *)error; 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /JSON/NSString+SBJSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "NSString+SBJSON.h" 31 | #import "SBJsonParser.h" 32 | 33 | @implementation NSString (NSString_SBJSON) 34 | 35 | - (id)JSONFragmentValue 36 | { 37 | SBJsonParser *jsonParser = [SBJsonParser new]; 38 | id repr = [jsonParser fragmentWithString:self]; 39 | if (!repr) 40 | NSLog(@"-JSONFragmentValue failed. Error trace is: %@", [jsonParser errorTrace]); 41 | [jsonParser release]; 42 | return repr; 43 | } 44 | 45 | - (id)JSONValue 46 | { 47 | SBJsonParser *jsonParser = [SBJsonParser new]; 48 | id repr = [jsonParser objectWithString:self]; 49 | if (!repr) 50 | NSLog(@"-JSONValue failed. Error trace is: %@", [jsonParser errorTrace]); 51 | [jsonParser release]; 52 | return repr; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /JSON/NSObject+SBJSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "NSObject+SBJSON.h" 31 | #import "SBJsonWriter.h" 32 | 33 | @implementation NSObject (NSObject_SBJSON) 34 | 35 | - (NSString *)JSONFragment { 36 | SBJsonWriter *jsonWriter = [SBJsonWriter new]; 37 | NSString *json = [jsonWriter stringWithFragment:self]; 38 | if (!json) 39 | NSLog(@"-JSONFragment failed. Error trace is: %@", [jsonWriter errorTrace]); 40 | [jsonWriter release]; 41 | return json; 42 | } 43 | 44 | - (NSString *)JSONRepresentation { 45 | SBJsonWriter *jsonWriter = [SBJsonWriter new]; 46 | NSString *json = [jsonWriter stringWithObject:self]; 47 | if (!json) 48 | NSLog(@"-JSONRepresentation failed. Error trace is: %@", [jsonWriter errorTrace]); 49 | [jsonWriter release]; 50 | return json; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /JSON/JSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | /** 31 | @mainpage A strict JSON parser and generator for Objective-C 32 | 33 | JSON (JavaScript Object Notation) is a lightweight data-interchange 34 | format. This framework provides two apis for parsing and generating 35 | JSON. One standard object-based and a higher level api consisting of 36 | categories added to existing Objective-C classes. 37 | 38 | Learn more on the http://code.google.com/p/json-framework project site. 39 | 40 | This framework does its best to be as strict as possible, both in what it 41 | accepts and what it generates. For example, it does not support trailing commas 42 | in arrays or objects. Nor does it support embedded comments, or 43 | anything else not in the JSON specification. This is considered a feature. 44 | 45 | */ 46 | 47 | #import "SBJSON.h" 48 | #import "NSObject+SBJSON.h" 49 | #import "NSString+SBJSON.h" 50 | 51 | -------------------------------------------------------------------------------- /JSON/NSString+SBJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | 32 | /** 33 | @brief Adds JSON parsing methods to NSString 34 | 35 | This is a category on NSString that adds methods for parsing the target string. 36 | */ 37 | @interface NSString (NSString_SBJSON) 38 | 39 | 40 | /** 41 | @brief Returns the object represented in the receiver, or nil on error. 42 | 43 | Returns a a scalar object represented by the string's JSON fragment representation. 44 | 45 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 46 | */ 47 | - (id)JSONFragmentValue; 48 | 49 | /** 50 | @brief Returns the NSDictionary or NSArray represented by the current string's JSON representation. 51 | 52 | Returns the dictionary or array represented in the receiver, or nil on error. 53 | 54 | Returns the NSDictionary or NSArray represented by the current string's JSON representation. 55 | */ 56 | - (id)JSONValue; 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /JSON/NSObject+SBJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | 32 | 33 | /** 34 | @brief Adds JSON generation to Foundation classes 35 | 36 | This is a category on NSObject that adds methods for returning JSON representations 37 | of standard objects to the objects themselves. This means you can call the 38 | -JSONRepresentation method on an NSArray object and it'll do what you want. 39 | */ 40 | @interface NSObject (NSObject_SBJSON) 41 | 42 | /** 43 | @brief Returns a string containing the receiver encoded as a JSON fragment. 44 | 45 | This method is added as a category on NSObject but is only actually 46 | supported for the following objects: 47 | @li NSDictionary 48 | @li NSArray 49 | @li NSString 50 | @li NSNumber (also used for booleans) 51 | @li NSNull 52 | 53 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 54 | */ 55 | - (NSString *)JSONFragment; 56 | 57 | /** 58 | @brief Returns a string containing the receiver encoded in JSON. 59 | 60 | This method is added as a category on NSObject but is only actually 61 | supported for the following objects: 62 | @li NSDictionary 63 | @li NSArray 64 | */ 65 | - (NSString *)JSONRepresentation; 66 | 67 | @end 68 | 69 | -------------------------------------------------------------------------------- /JSON/SBJsonBase.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJsonBase.h" 31 | NSString * SBJSONErrorDomain = @"org.brautaset.JSON.ErrorDomain"; 32 | 33 | 34 | @implementation SBJsonBase 35 | 36 | @synthesize errorTrace; 37 | @synthesize maxDepth; 38 | 39 | - (id)init { 40 | self = [super init]; 41 | if (self) 42 | self.maxDepth = 512; 43 | return self; 44 | } 45 | 46 | - (void)dealloc { 47 | [errorTrace release]; 48 | [super dealloc]; 49 | } 50 | 51 | - (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str { 52 | NSDictionary *userInfo; 53 | if (!errorTrace) { 54 | errorTrace = [NSMutableArray new]; 55 | userInfo = [NSDictionary dictionaryWithObject:str forKey:NSLocalizedDescriptionKey]; 56 | 57 | } else { 58 | userInfo = [NSDictionary dictionaryWithObjectsAndKeys: 59 | str, NSLocalizedDescriptionKey, 60 | [errorTrace lastObject], NSUnderlyingErrorKey, 61 | nil]; 62 | } 63 | 64 | NSError *error = [NSError errorWithDomain:SBJSONErrorDomain code:code userInfo:userInfo]; 65 | 66 | [self willChangeValueForKey:@"errorTrace"]; 67 | [errorTrace addObject:error]; 68 | [self didChangeValueForKey:@"errorTrace"]; 69 | } 70 | 71 | - (void)clearErrorTrace { 72 | [self willChangeValueForKey:@"errorTrace"]; 73 | [errorTrace release]; 74 | errorTrace = nil; 75 | [self didChangeValueForKey:@"errorTrace"]; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /JSON/SBJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | #import "SBJsonParser.h" 32 | #import "SBJsonWriter.h" 33 | 34 | /** 35 | @brief Facade for SBJsonWriter/SBJsonParser. 36 | 37 | Requests are forwarded to instances of SBJsonWriter and SBJsonParser. 38 | */ 39 | @interface SBJSON : SBJsonBase { 40 | 41 | @private 42 | SBJsonParser *jsonParser; 43 | SBJsonWriter *jsonWriter; 44 | } 45 | 46 | 47 | /// Return the fragment represented by the given string 48 | - (id)fragmentWithString:(NSString*)jsonrep 49 | error:(NSError**)error; 50 | 51 | /// Return the object represented by the given string 52 | - (id)objectWithString:(NSString*)jsonrep 53 | error:(NSError**)error; 54 | 55 | /// Parse the string and return the represented object (or scalar) 56 | - (id)objectWithString:(id)value 57 | allowScalar:(BOOL)x 58 | error:(NSError**)error; 59 | 60 | 61 | /// Return JSON representation of an array or dictionary 62 | - (NSString*)stringWithObject:(id)value 63 | error:(NSError**)error; 64 | 65 | /// Return JSON representation of any legal JSON value 66 | - (NSString*)stringWithFragment:(id)value 67 | error:(NSError**)error; 68 | 69 | /// Return JSON representation (or fragment) for the given object 70 | - (NSString*)stringWithObject:(id)value 71 | allowScalar:(BOOL)x 72 | error:(NSError**)error; 73 | 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /JSON/SBJsonBase.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | 32 | extern NSString * SBJSONErrorDomain; 33 | 34 | 35 | enum { 36 | EUNSUPPORTED = 1, 37 | EPARSENUM, 38 | EPARSE, 39 | EFRAGMENT, 40 | ECTRL, 41 | EUNICODE, 42 | EDEPTH, 43 | EESCAPE, 44 | ETRAILCOMMA, 45 | ETRAILGARBAGE, 46 | EEOF, 47 | EINPUT 48 | }; 49 | 50 | /** 51 | @brief Common base class for parsing & writing. 52 | 53 | This class contains the common error-handling code and option between the parser/writer. 54 | */ 55 | @interface SBJsonBase : NSObject { 56 | NSMutableArray *errorTrace; 57 | 58 | @protected 59 | NSUInteger depth, maxDepth; 60 | } 61 | 62 | /** 63 | @brief The maximum recursing depth. 64 | 65 | Defaults to 512. If the input is nested deeper than this the input will be deemed to be 66 | malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can 67 | turn off this security feature by setting the maxDepth value to 0. 68 | */ 69 | @property NSUInteger maxDepth; 70 | 71 | /** 72 | @brief Return an error trace, or nil if there was no errors. 73 | 74 | Note that this method returns the trace of the last method that failed. 75 | You need to check the return value of the call you're making to figure out 76 | if the call actually failed, before you know call this method. 77 | */ 78 | @property(copy,readonly) NSArray* errorTrace; 79 | 80 | /// @internal for use in subclasses to add errors to the stack trace 81 | - (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str; 82 | 83 | /// @internal for use in subclasess to clear the error before a new parsing attempt 84 | - (void)clearErrorTrace; 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /JSON/SBJsonParser.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | #import "SBJsonBase.h" 32 | 33 | /** 34 | @brief Options for the parser class. 35 | 36 | This exists so the SBJSON facade can implement the options in the parser without having to re-declare them. 37 | */ 38 | @protocol SBJsonParser 39 | 40 | /** 41 | @brief Return the object represented by the given string. 42 | 43 | Returns the object represented by the passed-in string or nil on error. The returned object can be 44 | a string, number, boolean, null, array or dictionary. 45 | 46 | @param repr the json string to parse 47 | */ 48 | - (id)objectWithString:(NSString *)repr; 49 | 50 | @end 51 | 52 | 53 | /** 54 | @brief The JSON parser class. 55 | 56 | JSON is mapped to Objective-C types in the following way: 57 | 58 | @li Null -> NSNull 59 | @li String -> NSMutableString 60 | @li Array -> NSMutableArray 61 | @li Object -> NSMutableDictionary 62 | @li Boolean -> NSNumber (initialised with -initWithBool:) 63 | @li Number -> NSDecimalNumber 64 | 65 | Since Objective-C doesn't have a dedicated class for boolean values, these turns into NSNumber 66 | instances. These are initialised with the -initWithBool: method, and 67 | round-trip back to JSON properly. (They won't silently suddenly become 0 or 1; they'll be 68 | represented as 'true' and 'false' again.) 69 | 70 | JSON numbers turn into NSDecimalNumber instances, 71 | as we can thus avoid any loss of precision. (JSON allows ridiculously large numbers.) 72 | 73 | */ 74 | @interface SBJsonParser : SBJsonBase { 75 | 76 | @private 77 | const char *c; 78 | } 79 | 80 | @end 81 | 82 | // don't use - exists for backwards compatibility with 2.1.x only. Will be removed in 2.3. 83 | @interface SBJsonParser (Private) 84 | - (id)fragmentWithString:(id)repr; 85 | @end 86 | 87 | 88 | -------------------------------------------------------------------------------- /Classes/MRTranslationOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // MRTranslationOperation.m 3 | // TranslationKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "MRTranslationOperation.h" 9 | 10 | #import "JSON.h" 11 | 12 | @implementation MRTranslationOperation 13 | 14 | #define kTranslateURLFormat @"http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=%@&langpair=%@%%7C%@" 15 | 16 | @synthesize sourceLanguageCode, delegate; 17 | 18 | - (id)init { 19 | return [self initWithSourceString:nil destinationLanguageCode:nil]; 20 | } 21 | 22 | - (id)initWithSourceString:(NSString *)source destinationLanguageCode:(NSString *)code { 23 | NSParameterAssert(source != nil); 24 | NSParameterAssert(code != nil); 25 | 26 | self = [super init]; 27 | if (self) { 28 | sourceString = [[source stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] retain]; 29 | sourceLanguageCode = [@"" retain]; 30 | destLanguageCode = [code copy]; 31 | } 32 | return self; 33 | } 34 | 35 | - (void)failedWithError:(NSError *)error { 36 | if ([delegate respondsToSelector:@selector(translationOperation:didFailWithError:)]) { 37 | [delegate translationOperation:self 38 | didFailWithError:[[error retain] autorelease]]; 39 | } 40 | } 41 | 42 | - (void)finishedWithResponse:(NSString *)response { 43 | if ([delegate respondsToSelector:@selector(translationOperation:didFinishTranslatingText:)]) { 44 | [delegate translationOperation:self 45 | didFinishTranslatingText:[[response retain] autorelease]]; 46 | } 47 | } 48 | 49 | - (void)main { 50 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 51 | 52 | NSString *urlString = [NSString stringWithFormat:kTranslateURLFormat, 53 | sourceString, 54 | sourceLanguageCode, 55 | destLanguageCode, nil]; 56 | 57 | NSURL *url = [NSURL URLWithString:urlString]; 58 | 59 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 60 | [request setValue:@"www.mattrajca.com" forHTTPHeaderField:@"Referrer"]; 61 | 62 | NSError *error = nil; 63 | 64 | NSData *data = [NSURLConnection sendSynchronousRequest:request 65 | returningResponse:nil 66 | error:&error]; 67 | 68 | if (!data) { 69 | [self performSelectorOnMainThread:@selector(failedWithError:) 70 | withObject:error 71 | waitUntilDone:NO]; 72 | 73 | return; 74 | } 75 | 76 | NSString *dataString = [[NSString alloc] initWithData:data 77 | encoding:NSASCIIStringEncoding]; 78 | 79 | NSDictionary *response = [dataString JSONValue]; 80 | [dataString release]; 81 | 82 | int statusCode = [[response objectForKey:@"responseStatus"] intValue]; 83 | 84 | if (!response || statusCode != 200) { 85 | NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain 86 | code:-1 87 | userInfo:nil]; 88 | 89 | [self performSelectorOnMainThread:@selector(failedWithError:) 90 | withObject:error 91 | waitUntilDone:NO]; 92 | 93 | return; 94 | } 95 | 96 | NSDictionary *responseData = [response objectForKey:@"responseData"]; 97 | NSString *translatedText = [responseData objectForKey:@"translatedText"]; 98 | 99 | [self performSelectorOnMainThread:@selector(finishedWithResponse:) 100 | withObject:translatedText 101 | waitUntilDone:NO]; 102 | 103 | [pool drain]; 104 | } 105 | 106 | - (void)dealloc { 107 | [sourceString release]; 108 | [destLanguageCode release]; 109 | [sourceLanguageCode release]; 110 | 111 | [super dealloc]; 112 | } 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /JSON/SBJsonWriter.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | #import "SBJsonBase.h" 32 | 33 | /** 34 | @brief Options for the writer class. 35 | 36 | This exists so the SBJSON facade can implement the options in the writer without having to re-declare them. 37 | */ 38 | @protocol SBJsonWriter 39 | 40 | /** 41 | @brief Whether we are generating human-readable (multiline) JSON. 42 | 43 | Set whether or not to generate human-readable JSON. The default is NO, which produces 44 | JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable 45 | JSON with linebreaks after each array value and dictionary key/value pair, indented two 46 | spaces per nesting level. 47 | */ 48 | @property BOOL humanReadable; 49 | 50 | /** 51 | @brief Whether or not to sort the dictionary keys in the output. 52 | 53 | If this is set to YES, the dictionary keys in the JSON output will be in sorted order. 54 | (This is useful if you need to compare two structures, for example.) The default is NO. 55 | */ 56 | @property BOOL sortKeys; 57 | 58 | /** 59 | @brief Return JSON representation (or fragment) for the given object. 60 | 61 | Returns a string containing JSON representation of the passed in value, or nil on error. 62 | If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. 63 | 64 | @param value any instance that can be represented as a JSON fragment 65 | 66 | */ 67 | - (NSString*)stringWithObject:(id)value; 68 | 69 | @end 70 | 71 | 72 | /** 73 | @brief The JSON writer class. 74 | 75 | Objective-C types are mapped to JSON types in the following way: 76 | 77 | @li NSNull -> Null 78 | @li NSString -> String 79 | @li NSArray -> Array 80 | @li NSDictionary -> Object 81 | @li NSNumber (-initWithBool:) -> Boolean 82 | @li NSNumber -> Number 83 | 84 | In JSON the keys of an object must be strings. NSDictionary keys need 85 | not be, but attempting to convert an NSDictionary with non-string keys 86 | into JSON will throw an exception. 87 | 88 | NSNumber instances created with the +initWithBool: method are 89 | converted into the JSON boolean "true" and "false" values, and vice 90 | versa. Any other NSNumber instances are converted to a JSON number the 91 | way you would expect. 92 | 93 | */ 94 | @interface SBJsonWriter : SBJsonBase { 95 | 96 | @private 97 | BOOL sortKeys, humanReadable; 98 | } 99 | 100 | @end 101 | 102 | // don't use - exists for backwards compatibility. Will be removed in 2.3. 103 | @interface SBJsonWriter (Private) 104 | - (NSString*)stringWithFragment:(id)value; 105 | @end 106 | 107 | /** 108 | @brief Allows generation of JSON for otherwise unsupported classes. 109 | 110 | If you have a custom class that you want to create a JSON representation for you can implement 111 | this method in your class. It should return a representation of your object defined 112 | in terms of objects that can be translated into JSON. For example, a Person 113 | object might implement it like this: 114 | 115 | @code 116 | - (id)jsonProxyObject { 117 | return [NSDictionary dictionaryWithObjectsAndKeys: 118 | name, @"name", 119 | phone, @"phone", 120 | email, @"email", 121 | nil]; 122 | } 123 | @endcode 124 | 125 | */ 126 | @interface NSObject (SBProxyForJson) 127 | - (id)proxyForJson; 128 | @end 129 | 130 | -------------------------------------------------------------------------------- /JSON/SBJSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJSON.h" 31 | 32 | @implementation SBJSON 33 | 34 | - (id)init { 35 | self = [super init]; 36 | if (self) { 37 | jsonWriter = [SBJsonWriter new]; 38 | jsonParser = [SBJsonParser new]; 39 | [self setMaxDepth:512]; 40 | 41 | } 42 | return self; 43 | } 44 | 45 | - (void)dealloc { 46 | [jsonWriter release]; 47 | [jsonParser release]; 48 | [super dealloc]; 49 | } 50 | 51 | #pragma mark Writer 52 | 53 | 54 | - (NSString *)stringWithObject:(id)obj { 55 | NSString *repr = [jsonWriter stringWithObject:obj]; 56 | if (repr) 57 | return repr; 58 | 59 | [errorTrace release]; 60 | errorTrace = [[jsonWriter errorTrace] mutableCopy]; 61 | return nil; 62 | } 63 | 64 | /** 65 | Returns a string containing JSON representation of the passed in value, or nil on error. 66 | If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. 67 | 68 | @param value any instance that can be represented as a JSON fragment 69 | @param allowScalar wether to return json fragments for scalar objects 70 | @param error used to return an error by reference (pass NULL if this is not desired) 71 | 72 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 73 | */ 74 | - (NSString*)stringWithObject:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error { 75 | 76 | NSString *json = allowScalar ? [jsonWriter stringWithFragment:value] : [jsonWriter stringWithObject:value]; 77 | if (json) 78 | return json; 79 | 80 | [errorTrace release]; 81 | errorTrace = [[jsonWriter errorTrace] mutableCopy]; 82 | 83 | if (error) 84 | *error = [errorTrace lastObject]; 85 | return nil; 86 | } 87 | 88 | /** 89 | Returns a string containing JSON representation of the passed in value, or nil on error. 90 | If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error. 91 | 92 | @param value any instance that can be represented as a JSON fragment 93 | @param error used to return an error by reference (pass NULL if this is not desired) 94 | 95 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 96 | */ 97 | - (NSString*)stringWithFragment:(id)value error:(NSError**)error { 98 | return [self stringWithObject:value 99 | allowScalar:YES 100 | error:error]; 101 | } 102 | 103 | /** 104 | Returns a string containing JSON representation of the passed in value, or nil on error. 105 | If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error. 106 | 107 | @param value a NSDictionary or NSArray instance 108 | @param error used to return an error by reference (pass NULL if this is not desired) 109 | */ 110 | - (NSString*)stringWithObject:(id)value error:(NSError**)error { 111 | return [self stringWithObject:value 112 | allowScalar:NO 113 | error:error]; 114 | } 115 | 116 | #pragma mark Parsing 117 | 118 | - (id)objectWithString:(NSString *)repr { 119 | id obj = [jsonParser objectWithString:repr]; 120 | if (obj) 121 | return obj; 122 | 123 | [errorTrace release]; 124 | errorTrace = [[jsonParser errorTrace] mutableCopy]; 125 | 126 | return nil; 127 | } 128 | 129 | /** 130 | Returns the object represented by the passed-in string or nil on error. The returned object can be 131 | a string, number, boolean, null, array or dictionary. 132 | 133 | @param value the json string to parse 134 | @param allowScalar whether to return objects for JSON fragments 135 | @param error used to return an error by reference (pass NULL if this is not desired) 136 | 137 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 138 | */ 139 | - (id)objectWithString:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error { 140 | 141 | id obj = allowScalar ? [jsonParser fragmentWithString:value] : [jsonParser objectWithString:value]; 142 | if (obj) 143 | return obj; 144 | 145 | [errorTrace release]; 146 | errorTrace = [[jsonParser errorTrace] mutableCopy]; 147 | 148 | if (error) 149 | *error = [errorTrace lastObject]; 150 | return nil; 151 | } 152 | 153 | /** 154 | Returns the object represented by the passed-in string or nil on error. The returned object can be 155 | a string, number, boolean, null, array or dictionary. 156 | 157 | @param repr the json string to parse 158 | @param error used to return an error by reference (pass NULL if this is not desired) 159 | 160 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 161 | */ 162 | - (id)fragmentWithString:(NSString*)repr error:(NSError**)error { 163 | return [self objectWithString:repr 164 | allowScalar:YES 165 | error:error]; 166 | } 167 | 168 | /** 169 | Returns the object represented by the passed-in string or nil on error. The returned object 170 | will be either a dictionary or an array. 171 | 172 | @param repr the json string to parse 173 | @param error used to return an error by reference (pass NULL if this is not desired) 174 | */ 175 | - (id)objectWithString:(NSString*)repr error:(NSError**)error { 176 | return [self objectWithString:repr 177 | allowScalar:NO 178 | error:error]; 179 | } 180 | 181 | 182 | 183 | #pragma mark Properties - parsing 184 | 185 | - (NSUInteger)maxDepth { 186 | return jsonParser.maxDepth; 187 | } 188 | 189 | - (void)setMaxDepth:(NSUInteger)d { 190 | jsonWriter.maxDepth = jsonParser.maxDepth = d; 191 | } 192 | 193 | 194 | #pragma mark Properties - writing 195 | 196 | - (BOOL)humanReadable { 197 | return jsonWriter.humanReadable; 198 | } 199 | 200 | - (void)setHumanReadable:(BOOL)x { 201 | jsonWriter.humanReadable = x; 202 | } 203 | 204 | - (BOOL)sortKeys { 205 | return jsonWriter.sortKeys; 206 | } 207 | 208 | - (void)setSortKeys:(BOOL)x { 209 | jsonWriter.sortKeys = x; 210 | } 211 | 212 | @end 213 | -------------------------------------------------------------------------------- /JSON/SBJsonWriter.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJsonWriter.h" 31 | 32 | @interface SBJsonWriter () 33 | 34 | - (BOOL)appendValue:(id)fragment into:(NSMutableString*)json; 35 | - (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json; 36 | - (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json; 37 | - (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json; 38 | 39 | - (NSString*)indent; 40 | 41 | @end 42 | 43 | @implementation SBJsonWriter 44 | 45 | static NSMutableCharacterSet *kEscapeChars; 46 | 47 | + (void)initialize { 48 | kEscapeChars = [[NSMutableCharacterSet characterSetWithRange: NSMakeRange(0,32)] retain]; 49 | [kEscapeChars addCharactersInString: @"\"\\"]; 50 | } 51 | 52 | 53 | @synthesize sortKeys; 54 | @synthesize humanReadable; 55 | 56 | /** 57 | @deprecated This exists in order to provide fragment support in older APIs in one more version. 58 | It should be removed in the next major version. 59 | */ 60 | - (NSString*)stringWithFragment:(id)value { 61 | [self clearErrorTrace]; 62 | depth = 0; 63 | NSMutableString *json = [NSMutableString stringWithCapacity:128]; 64 | 65 | if ([self appendValue:value into:json]) 66 | return json; 67 | 68 | return nil; 69 | } 70 | 71 | 72 | - (NSString*)stringWithObject:(id)value { 73 | 74 | if ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]) { 75 | return [self stringWithFragment:value]; 76 | } 77 | 78 | if ([value respondsToSelector:@selector(proxyForJson)]) { 79 | NSString *tmp = [self stringWithObject:[value proxyForJson]]; 80 | if (tmp) 81 | return tmp; 82 | } 83 | 84 | 85 | [self clearErrorTrace]; 86 | [self addErrorWithCode:EFRAGMENT description:@"Not valid type for JSON"]; 87 | return nil; 88 | } 89 | 90 | 91 | - (NSString*)indent { 92 | return [@"\n" stringByPaddingToLength:1 + 2 * depth withString:@" " startingAtIndex:0]; 93 | } 94 | 95 | - (BOOL)appendValue:(id)fragment into:(NSMutableString*)json { 96 | if ([fragment isKindOfClass:[NSDictionary class]]) { 97 | if (![self appendDictionary:fragment into:json]) 98 | return NO; 99 | 100 | } else if ([fragment isKindOfClass:[NSArray class]]) { 101 | if (![self appendArray:fragment into:json]) 102 | return NO; 103 | 104 | } else if ([fragment isKindOfClass:[NSString class]]) { 105 | if (![self appendString:fragment into:json]) 106 | return NO; 107 | 108 | } else if ([fragment isKindOfClass:[NSNumber class]]) { 109 | if ('c' == *[fragment objCType]) 110 | [json appendString:[fragment boolValue] ? @"true" : @"false"]; 111 | else 112 | [json appendString:[fragment stringValue]]; 113 | 114 | } else if ([fragment isKindOfClass:[NSNull class]]) { 115 | [json appendString:@"null"]; 116 | } else if ([fragment respondsToSelector:@selector(proxyForJson)]) { 117 | [self appendValue:[fragment proxyForJson] into:json]; 118 | 119 | } else { 120 | [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"JSON serialisation not supported for %@", [fragment class]]]; 121 | return NO; 122 | } 123 | return YES; 124 | } 125 | 126 | - (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json { 127 | if (maxDepth && ++depth > maxDepth) { 128 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 129 | return NO; 130 | } 131 | [json appendString:@"["]; 132 | 133 | BOOL addComma = NO; 134 | for (id value in fragment) { 135 | if (addComma) 136 | [json appendString:@","]; 137 | else 138 | addComma = YES; 139 | 140 | if ([self humanReadable]) 141 | [json appendString:[self indent]]; 142 | 143 | if (![self appendValue:value into:json]) { 144 | return NO; 145 | } 146 | } 147 | 148 | depth--; 149 | if ([self humanReadable] && [fragment count]) 150 | [json appendString:[self indent]]; 151 | [json appendString:@"]"]; 152 | return YES; 153 | } 154 | 155 | - (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json { 156 | if (maxDepth && ++depth > maxDepth) { 157 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 158 | return NO; 159 | } 160 | [json appendString:@"{"]; 161 | 162 | NSString *colon = [self humanReadable] ? @" : " : @":"; 163 | BOOL addComma = NO; 164 | NSArray *keys = [fragment allKeys]; 165 | if (self.sortKeys) 166 | keys = [keys sortedArrayUsingSelector:@selector(compare:)]; 167 | 168 | for (id value in keys) { 169 | if (addComma) 170 | [json appendString:@","]; 171 | else 172 | addComma = YES; 173 | 174 | if ([self humanReadable]) 175 | [json appendString:[self indent]]; 176 | 177 | if (![value isKindOfClass:[NSString class]]) { 178 | [self addErrorWithCode:EUNSUPPORTED description: @"JSON object key must be string"]; 179 | return NO; 180 | } 181 | 182 | if (![self appendString:value into:json]) 183 | return NO; 184 | 185 | [json appendString:colon]; 186 | if (![self appendValue:[fragment objectForKey:value] into:json]) { 187 | [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"Unsupported value for key %@ in object", value]]; 188 | return NO; 189 | } 190 | } 191 | 192 | depth--; 193 | if ([self humanReadable] && [fragment count]) 194 | [json appendString:[self indent]]; 195 | [json appendString:@"}"]; 196 | return YES; 197 | } 198 | 199 | - (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json { 200 | 201 | [json appendString:@"\""]; 202 | 203 | NSRange esc = [fragment rangeOfCharacterFromSet:kEscapeChars]; 204 | if ( !esc.length ) { 205 | // No special chars -- can just add the raw string: 206 | [json appendString:fragment]; 207 | 208 | } else { 209 | NSUInteger length = [fragment length]; 210 | for (NSUInteger i = 0; i < length; i++) { 211 | unichar uc = [fragment characterAtIndex:i]; 212 | switch (uc) { 213 | case '"': [json appendString:@"\\\""]; break; 214 | case '\\': [json appendString:@"\\\\"]; break; 215 | case '\t': [json appendString:@"\\t"]; break; 216 | case '\n': [json appendString:@"\\n"]; break; 217 | case '\r': [json appendString:@"\\r"]; break; 218 | case '\b': [json appendString:@"\\b"]; break; 219 | case '\f': [json appendString:@"\\f"]; break; 220 | default: 221 | if (uc < 0x20) { 222 | [json appendFormat:@"\\u%04x", uc]; 223 | } else { 224 | CFStringAppendCharacters((CFMutableStringRef)json, &uc, 1); 225 | } 226 | break; 227 | 228 | } 229 | } 230 | } 231 | 232 | [json appendString:@"\""]; 233 | return YES; 234 | } 235 | 236 | 237 | @end 238 | -------------------------------------------------------------------------------- /JSON/SBJsonParser.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJsonParser.h" 31 | 32 | @interface SBJsonParser () 33 | 34 | - (BOOL)scanValue:(NSObject **)o; 35 | 36 | - (BOOL)scanRestOfArray:(NSMutableArray **)o; 37 | - (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o; 38 | - (BOOL)scanRestOfNull:(NSNull **)o; 39 | - (BOOL)scanRestOfFalse:(NSNumber **)o; 40 | - (BOOL)scanRestOfTrue:(NSNumber **)o; 41 | - (BOOL)scanRestOfString:(NSMutableString **)o; 42 | 43 | // Cannot manage without looking at the first digit 44 | - (BOOL)scanNumber:(NSNumber **)o; 45 | 46 | - (BOOL)scanHexQuad:(unichar *)x; 47 | - (BOOL)scanUnicodeChar:(unichar *)x; 48 | 49 | - (BOOL)scanIsAtEnd; 50 | 51 | @end 52 | 53 | #define skipWhitespace(c) while (isspace(*c)) c++ 54 | #define skipDigits(c) while (isdigit(*c)) c++ 55 | 56 | 57 | @implementation SBJsonParser 58 | 59 | static char ctrl[0x22]; 60 | 61 | 62 | + (void)initialize { 63 | ctrl[0] = '\"'; 64 | ctrl[1] = '\\'; 65 | for (int i = 1; i < 0x20; i++) 66 | ctrl[i+1] = i; 67 | ctrl[0x21] = 0; 68 | } 69 | 70 | /** 71 | @deprecated This exists in order to provide fragment support in older APIs in one more version. 72 | It should be removed in the next major version. 73 | */ 74 | - (id)fragmentWithString:(id)repr { 75 | [self clearErrorTrace]; 76 | 77 | if (!repr) { 78 | [self addErrorWithCode:EINPUT description:@"Input was 'nil'"]; 79 | return nil; 80 | } 81 | 82 | depth = 0; 83 | c = [repr UTF8String]; 84 | 85 | id o; 86 | if (![self scanValue:&o]) { 87 | return nil; 88 | } 89 | 90 | // We found some valid JSON. But did it also contain something else? 91 | if (![self scanIsAtEnd]) { 92 | [self addErrorWithCode:ETRAILGARBAGE description:@"Garbage after JSON"]; 93 | return nil; 94 | } 95 | 96 | NSAssert1(o, @"Should have a valid object from %@", repr); 97 | return o; 98 | } 99 | 100 | - (id)objectWithString:(NSString *)repr { 101 | 102 | id o = [self fragmentWithString:repr]; 103 | if (!o) 104 | return nil; 105 | 106 | // Check that the object we've found is a valid JSON container. 107 | if (![o isKindOfClass:[NSDictionary class]] && ![o isKindOfClass:[NSArray class]]) { 108 | [self addErrorWithCode:EFRAGMENT description:@"Valid fragment, but not JSON"]; 109 | return nil; 110 | } 111 | 112 | return o; 113 | } 114 | 115 | /* 116 | In contrast to the public methods, it is an error to omit the error parameter here. 117 | */ 118 | - (BOOL)scanValue:(NSObject **)o 119 | { 120 | skipWhitespace(c); 121 | 122 | switch (*c++) { 123 | case '{': 124 | return [self scanRestOfDictionary:(NSMutableDictionary **)o]; 125 | break; 126 | case '[': 127 | return [self scanRestOfArray:(NSMutableArray **)o]; 128 | break; 129 | case '"': 130 | return [self scanRestOfString:(NSMutableString **)o]; 131 | break; 132 | case 'f': 133 | return [self scanRestOfFalse:(NSNumber **)o]; 134 | break; 135 | case 't': 136 | return [self scanRestOfTrue:(NSNumber **)o]; 137 | break; 138 | case 'n': 139 | return [self scanRestOfNull:(NSNull **)o]; 140 | break; 141 | case '-': 142 | case '0'...'9': 143 | c--; // cannot verify number correctly without the first character 144 | return [self scanNumber:(NSNumber **)o]; 145 | break; 146 | case '+': 147 | [self addErrorWithCode:EPARSENUM description: @"Leading + disallowed in number"]; 148 | return NO; 149 | break; 150 | case 0x0: 151 | [self addErrorWithCode:EEOF description:@"Unexpected end of string"]; 152 | return NO; 153 | break; 154 | default: 155 | [self addErrorWithCode:EPARSE description: @"Unrecognised leading character"]; 156 | return NO; 157 | break; 158 | } 159 | 160 | NSAssert(0, @"Should never get here"); 161 | return NO; 162 | } 163 | 164 | - (BOOL)scanRestOfTrue:(NSNumber **)o 165 | { 166 | if (!strncmp(c, "rue", 3)) { 167 | c += 3; 168 | *o = [NSNumber numberWithBool:YES]; 169 | return YES; 170 | } 171 | [self addErrorWithCode:EPARSE description:@"Expected 'true'"]; 172 | return NO; 173 | } 174 | 175 | - (BOOL)scanRestOfFalse:(NSNumber **)o 176 | { 177 | if (!strncmp(c, "alse", 4)) { 178 | c += 4; 179 | *o = [NSNumber numberWithBool:NO]; 180 | return YES; 181 | } 182 | [self addErrorWithCode:EPARSE description: @"Expected 'false'"]; 183 | return NO; 184 | } 185 | 186 | - (BOOL)scanRestOfNull:(NSNull **)o { 187 | if (!strncmp(c, "ull", 3)) { 188 | c += 3; 189 | *o = [NSNull null]; 190 | return YES; 191 | } 192 | [self addErrorWithCode:EPARSE description: @"Expected 'null'"]; 193 | return NO; 194 | } 195 | 196 | - (BOOL)scanRestOfArray:(NSMutableArray **)o { 197 | if (maxDepth && ++depth > maxDepth) { 198 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 199 | return NO; 200 | } 201 | 202 | *o = [NSMutableArray arrayWithCapacity:8]; 203 | 204 | for (; *c ;) { 205 | id v; 206 | 207 | skipWhitespace(c); 208 | if (*c == ']' && c++) { 209 | depth--; 210 | return YES; 211 | } 212 | 213 | if (![self scanValue:&v]) { 214 | [self addErrorWithCode:EPARSE description:@"Expected value while parsing array"]; 215 | return NO; 216 | } 217 | 218 | [*o addObject:v]; 219 | 220 | skipWhitespace(c); 221 | if (*c == ',' && c++) { 222 | skipWhitespace(c); 223 | if (*c == ']') { 224 | [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in array"]; 225 | return NO; 226 | } 227 | } 228 | } 229 | 230 | [self addErrorWithCode:EEOF description: @"End of input while parsing array"]; 231 | return NO; 232 | } 233 | 234 | - (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o 235 | { 236 | if (maxDepth && ++depth > maxDepth) { 237 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 238 | return NO; 239 | } 240 | 241 | *o = [NSMutableDictionary dictionaryWithCapacity:7]; 242 | 243 | for (; *c ;) { 244 | id k, v; 245 | 246 | skipWhitespace(c); 247 | if (*c == '}' && c++) { 248 | depth--; 249 | return YES; 250 | } 251 | 252 | if (!(*c == '\"' && c++ && [self scanRestOfString:&k])) { 253 | [self addErrorWithCode:EPARSE description: @"Object key string expected"]; 254 | return NO; 255 | } 256 | 257 | skipWhitespace(c); 258 | if (*c != ':') { 259 | [self addErrorWithCode:EPARSE description: @"Expected ':' separating key and value"]; 260 | return NO; 261 | } 262 | 263 | c++; 264 | if (![self scanValue:&v]) { 265 | NSString *string = [NSString stringWithFormat:@"Object value expected for key: %@", k]; 266 | [self addErrorWithCode:EPARSE description: string]; 267 | return NO; 268 | } 269 | 270 | [*o setObject:v forKey:k]; 271 | 272 | skipWhitespace(c); 273 | if (*c == ',' && c++) { 274 | skipWhitespace(c); 275 | if (*c == '}') { 276 | [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in object"]; 277 | return NO; 278 | } 279 | } 280 | } 281 | 282 | [self addErrorWithCode:EEOF description: @"End of input while parsing object"]; 283 | return NO; 284 | } 285 | 286 | - (BOOL)scanRestOfString:(NSMutableString **)o 287 | { 288 | *o = [NSMutableString stringWithCapacity:16]; 289 | do { 290 | // First see if there's a portion we can grab in one go. 291 | // Doing this caused a massive speedup on the long string. 292 | size_t len = strcspn(c, ctrl); 293 | if (len) { 294 | // check for 295 | id t = [[NSString alloc] initWithBytesNoCopy:(char*)c 296 | length:len 297 | encoding:NSUTF8StringEncoding 298 | freeWhenDone:NO]; 299 | if (t) { 300 | [*o appendString:t]; 301 | [t release]; 302 | c += len; 303 | } 304 | } 305 | 306 | if (*c == '"') { 307 | c++; 308 | return YES; 309 | 310 | } else if (*c == '\\') { 311 | unichar uc = *++c; 312 | switch (uc) { 313 | case '\\': 314 | case '/': 315 | case '"': 316 | break; 317 | 318 | case 'b': uc = '\b'; break; 319 | case 'n': uc = '\n'; break; 320 | case 'r': uc = '\r'; break; 321 | case 't': uc = '\t'; break; 322 | case 'f': uc = '\f'; break; 323 | 324 | case 'u': 325 | c++; 326 | if (![self scanUnicodeChar:&uc]) { 327 | [self addErrorWithCode:EUNICODE description: @"Broken unicode character"]; 328 | return NO; 329 | } 330 | c--; // hack. 331 | break; 332 | default: 333 | [self addErrorWithCode:EESCAPE description: [NSString stringWithFormat:@"Illegal escape sequence '0x%x'", uc]]; 334 | return NO; 335 | break; 336 | } 337 | CFStringAppendCharacters((CFMutableStringRef)*o, &uc, 1); 338 | c++; 339 | 340 | } else if (*c < 0x20) { 341 | [self addErrorWithCode:ECTRL description: [NSString stringWithFormat:@"Unescaped control character '0x%x'", *c]]; 342 | return NO; 343 | 344 | } else { 345 | NSLog(@"should not be able to get here"); 346 | } 347 | } while (*c); 348 | 349 | [self addErrorWithCode:EEOF description:@"Unexpected EOF while parsing string"]; 350 | return NO; 351 | } 352 | 353 | - (BOOL)scanUnicodeChar:(unichar *)x 354 | { 355 | unichar hi, lo; 356 | 357 | if (![self scanHexQuad:&hi]) { 358 | [self addErrorWithCode:EUNICODE description: @"Missing hex quad"]; 359 | return NO; 360 | } 361 | 362 | if (hi >= 0xd800) { // high surrogate char? 363 | if (hi < 0xdc00) { // yes - expect a low char 364 | 365 | if (!(*c == '\\' && ++c && *c == 'u' && ++c && [self scanHexQuad:&lo])) { 366 | [self addErrorWithCode:EUNICODE description: @"Missing low character in surrogate pair"]; 367 | return NO; 368 | } 369 | 370 | if (lo < 0xdc00 || lo >= 0xdfff) { 371 | [self addErrorWithCode:EUNICODE description:@"Invalid low surrogate char"]; 372 | return NO; 373 | } 374 | 375 | hi = (hi - 0xd800) * 0x400 + (lo - 0xdc00) + 0x10000; 376 | 377 | } else if (hi < 0xe000) { 378 | [self addErrorWithCode:EUNICODE description:@"Invalid high character in surrogate pair"]; 379 | return NO; 380 | } 381 | } 382 | 383 | *x = hi; 384 | return YES; 385 | } 386 | 387 | - (BOOL)scanHexQuad:(unichar *)x 388 | { 389 | *x = 0; 390 | for (int i = 0; i < 4; i++) { 391 | unichar uc = *c; 392 | c++; 393 | int d = (uc >= '0' && uc <= '9') 394 | ? uc - '0' : (uc >= 'a' && uc <= 'f') 395 | ? (uc - 'a' + 10) : (uc >= 'A' && uc <= 'F') 396 | ? (uc - 'A' + 10) : -1; 397 | if (d == -1) { 398 | [self addErrorWithCode:EUNICODE description:@"Missing hex digit in quad"]; 399 | return NO; 400 | } 401 | *x *= 16; 402 | *x += d; 403 | } 404 | return YES; 405 | } 406 | 407 | - (BOOL)scanNumber:(NSNumber **)o 408 | { 409 | const char *ns = c; 410 | 411 | // The logic to test for validity of the number formatting is relicensed 412 | // from JSON::XS with permission from its author Marc Lehmann. 413 | // (Available at the CPAN: http://search.cpan.org/dist/JSON-XS/ .) 414 | 415 | if ('-' == *c) 416 | c++; 417 | 418 | if ('0' == *c && c++) { 419 | if (isdigit(*c)) { 420 | [self addErrorWithCode:EPARSENUM description: @"Leading 0 disallowed in number"]; 421 | return NO; 422 | } 423 | 424 | } else if (!isdigit(*c) && c != ns) { 425 | [self addErrorWithCode:EPARSENUM description: @"No digits after initial minus"]; 426 | return NO; 427 | 428 | } else { 429 | skipDigits(c); 430 | } 431 | 432 | // Fractional part 433 | if ('.' == *c && c++) { 434 | 435 | if (!isdigit(*c)) { 436 | [self addErrorWithCode:EPARSENUM description: @"No digits after decimal point"]; 437 | return NO; 438 | } 439 | skipDigits(c); 440 | } 441 | 442 | // Exponential part 443 | if ('e' == *c || 'E' == *c) { 444 | c++; 445 | 446 | if ('-' == *c || '+' == *c) 447 | c++; 448 | 449 | if (!isdigit(*c)) { 450 | [self addErrorWithCode:EPARSENUM description: @"No digits after exponent"]; 451 | return NO; 452 | } 453 | skipDigits(c); 454 | } 455 | 456 | id str = [[NSString alloc] initWithBytesNoCopy:(char*)ns 457 | length:c - ns 458 | encoding:NSUTF8StringEncoding 459 | freeWhenDone:NO]; 460 | [str autorelease]; 461 | if (str && (*o = [NSDecimalNumber decimalNumberWithString:str])) 462 | return YES; 463 | 464 | [self addErrorWithCode:EPARSENUM description: @"Failed creating decimal instance"]; 465 | return NO; 466 | } 467 | 468 | - (BOOL)scanIsAtEnd 469 | { 470 | skipWhitespace(c); 471 | return !*c; 472 | } 473 | 474 | 475 | @end 476 | -------------------------------------------------------------------------------- /TranslationKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; 11 | 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; 12 | C98ADCBE11FF70BC0071FF73 /* TranslationKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C98ADCBD11FF70BC0071FF73 /* TranslationKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | C98ADE3411FF7D6A0071FF73 /* JSON.h in Headers */ = {isa = PBXBuildFile; fileRef = C98ADE2711FF7D6A0071FF73 /* JSON.h */; }; 14 | C98ADE3511FF7D6A0071FF73 /* NSObject+SBJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = C98ADE2811FF7D6A0071FF73 /* NSObject+SBJSON.h */; }; 15 | C98ADE3611FF7D6A0071FF73 /* NSObject+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = C98ADE2911FF7D6A0071FF73 /* NSObject+SBJSON.m */; }; 16 | C98ADE3711FF7D6A0071FF73 /* NSString+SBJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = C98ADE2A11FF7D6A0071FF73 /* NSString+SBJSON.h */; }; 17 | C98ADE3811FF7D6A0071FF73 /* NSString+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = C98ADE2B11FF7D6A0071FF73 /* NSString+SBJSON.m */; }; 18 | C98ADE3911FF7D6A0071FF73 /* SBJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = C98ADE2C11FF7D6A0071FF73 /* SBJSON.h */; }; 19 | C98ADE3A11FF7D6A0071FF73 /* SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = C98ADE2D11FF7D6A0071FF73 /* SBJSON.m */; }; 20 | C98ADE3B11FF7D6A0071FF73 /* SBJsonBase.h in Headers */ = {isa = PBXBuildFile; fileRef = C98ADE2E11FF7D6A0071FF73 /* SBJsonBase.h */; }; 21 | C98ADE3C11FF7D6A0071FF73 /* SBJsonBase.m in Sources */ = {isa = PBXBuildFile; fileRef = C98ADE2F11FF7D6A0071FF73 /* SBJsonBase.m */; }; 22 | C98ADE3D11FF7D6A0071FF73 /* SBJsonParser.h in Headers */ = {isa = PBXBuildFile; fileRef = C98ADE3011FF7D6A0071FF73 /* SBJsonParser.h */; }; 23 | C98ADE3E11FF7D6A0071FF73 /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C98ADE3111FF7D6A0071FF73 /* SBJsonParser.m */; }; 24 | C98ADE3F11FF7D6A0071FF73 /* SBJsonWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = C98ADE3211FF7D6A0071FF73 /* SBJsonWriter.h */; }; 25 | C98ADE4011FF7D6A0071FF73 /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = C98ADE3311FF7D6A0071FF73 /* SBJsonWriter.m */; }; 26 | C98ADE4511FF7D7B0071FF73 /* MRTranslationOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C98ADE4311FF7D7B0071FF73 /* MRTranslationOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 27 | C98ADE4611FF7D7B0071FF73 /* MRTranslationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C98ADE4411FF7D7B0071FF73 /* MRTranslationOperation.m */; }; 28 | C98ADF2411FF99A70071FF73 /* LogicTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C98ADF2311FF99A70071FF73 /* LogicTests.m */; }; 29 | C9E7FF151200A4E000FCC6FB /* TranslationKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* TranslationKit.framework */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXContainerItemProxy section */ 33 | C9E7FF001200A40000FCC6FB /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 8DC2EF4F0486A6940098B216; 38 | remoteInfo = TranslationKit; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 44 | 0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 45 | 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 46 | 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 47 | 32DBCF5E0370ADEE00C91783 /* TranslationKit_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TranslationKit_Prefix.pch; sourceTree = ""; }; 48 | 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | 8DC2EF5B0486A6940098B216 /* TranslationKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TranslationKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | C98ADCBD11FF70BC0071FF73 /* TranslationKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TranslationKit.h; sourceTree = ""; }; 51 | C98ADE2711FF7D6A0071FF73 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; 52 | C98ADE2811FF7D6A0071FF73 /* NSObject+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SBJSON.h"; sourceTree = ""; }; 53 | C98ADE2911FF7D6A0071FF73 /* NSObject+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SBJSON.m"; sourceTree = ""; }; 54 | C98ADE2A11FF7D6A0071FF73 /* NSString+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SBJSON.h"; sourceTree = ""; }; 55 | C98ADE2B11FF7D6A0071FF73 /* NSString+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SBJSON.m"; sourceTree = ""; }; 56 | C98ADE2C11FF7D6A0071FF73 /* SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJSON.h; sourceTree = ""; }; 57 | C98ADE2D11FF7D6A0071FF73 /* SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJSON.m; sourceTree = ""; }; 58 | C98ADE2E11FF7D6A0071FF73 /* SBJsonBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonBase.h; sourceTree = ""; }; 59 | C98ADE2F11FF7D6A0071FF73 /* SBJsonBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonBase.m; sourceTree = ""; }; 60 | C98ADE3011FF7D6A0071FF73 /* SBJsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonParser.h; sourceTree = ""; }; 61 | C98ADE3111FF7D6A0071FF73 /* SBJsonParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonParser.m; sourceTree = ""; }; 62 | C98ADE3211FF7D6A0071FF73 /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = ""; }; 63 | C98ADE3311FF7D6A0071FF73 /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = ""; }; 64 | C98ADE4311FF7D7B0071FF73 /* MRTranslationOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MRTranslationOperation.h; path = Classes/MRTranslationOperation.h; sourceTree = ""; }; 65 | C98ADE4411FF7D7B0071FF73 /* MRTranslationOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MRTranslationOperation.m; path = Classes/MRTranslationOperation.m; sourceTree = ""; }; 66 | C98ADF1B11FF99690071FF73 /* Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | C98ADF1C11FF99690071FF73 /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; }; 68 | C98ADF2211FF99A70071FF73 /* LogicTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LogicTests.h; path = Tests/LogicTests.h; sourceTree = ""; }; 69 | C98ADF2311FF99A70071FF73 /* LogicTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LogicTests.m; path = Tests/LogicTests.m; sourceTree = ""; }; 70 | D2F7E79907B2D74100F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; 71 | /* End PBXFileReference section */ 72 | 73 | /* Begin PBXFrameworksBuildPhase section */ 74 | 8DC2EF560486A6940098B216 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */, 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | C98ADF1811FF99690071FF73 /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | C9E7FF151200A4E000FCC6FB /* TranslationKit.framework in Frameworks */, 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | /* End PBXFrameworksBuildPhase section */ 91 | 92 | /* Begin PBXGroup section */ 93 | 034768DFFF38A50411DB9C8B /* Products */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 8DC2EF5B0486A6940098B216 /* TranslationKit.framework */, 97 | C98ADF1B11FF99690071FF73 /* Tests.octest */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | 0867D691FE84028FC02AAC07 /* TranslationKit */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 08FB77AEFE84172EC02AAC07 /* Classes */, 106 | 32C88DFF0371C24200C91783 /* Other Sources */, 107 | 089C1665FE841158C02AAC07 /* Resources */, 108 | 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, 109 | 034768DFFF38A50411DB9C8B /* Products */, 110 | ); 111 | name = TranslationKit; 112 | sourceTree = ""; 113 | }; 114 | 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */, 118 | 1058C7B2FEA5585E11CA2CBB /* Other Frameworks */, 119 | ); 120 | name = "External Frameworks and Libraries"; 121 | sourceTree = ""; 122 | }; 123 | 089C1665FE841158C02AAC07 /* Resources */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 8DC2EF5A0486A6940098B216 /* Info.plist */, 127 | 089C1666FE841158C02AAC07 /* InfoPlist.strings */, 128 | C98ADF1C11FF99690071FF73 /* Tests-Info.plist */, 129 | ); 130 | name = Resources; 131 | sourceTree = ""; 132 | }; 133 | 08FB77AEFE84172EC02AAC07 /* Classes */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | C98ADF2111FF99740071FF73 /* Core */, 137 | C98ADF2011FF996F0071FF73 /* Tests */, 138 | C98ADE2611FF7D6A0071FF73 /* JSON */, 139 | C98ADCBD11FF70BC0071FF73 /* TranslationKit.h */, 140 | ); 141 | name = Classes; 142 | sourceTree = ""; 143 | }; 144 | 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */, 148 | ); 149 | name = "Linked Frameworks"; 150 | sourceTree = ""; 151 | }; 152 | 1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 0867D6A5FE840307C02AAC07 /* AppKit.framework */, 156 | D2F7E79907B2D74100F64583 /* CoreData.framework */, 157 | 0867D69BFE84028FC02AAC07 /* Foundation.framework */, 158 | ); 159 | name = "Other Frameworks"; 160 | sourceTree = ""; 161 | }; 162 | 32C88DFF0371C24200C91783 /* Other Sources */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 32DBCF5E0370ADEE00C91783 /* TranslationKit_Prefix.pch */, 166 | ); 167 | name = "Other Sources"; 168 | sourceTree = ""; 169 | }; 170 | C98ADE2611FF7D6A0071FF73 /* JSON */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | C98ADE2711FF7D6A0071FF73 /* JSON.h */, 174 | C98ADE2811FF7D6A0071FF73 /* NSObject+SBJSON.h */, 175 | C98ADE2911FF7D6A0071FF73 /* NSObject+SBJSON.m */, 176 | C98ADE2A11FF7D6A0071FF73 /* NSString+SBJSON.h */, 177 | C98ADE2B11FF7D6A0071FF73 /* NSString+SBJSON.m */, 178 | C98ADE2C11FF7D6A0071FF73 /* SBJSON.h */, 179 | C98ADE2D11FF7D6A0071FF73 /* SBJSON.m */, 180 | C98ADE2E11FF7D6A0071FF73 /* SBJsonBase.h */, 181 | C98ADE2F11FF7D6A0071FF73 /* SBJsonBase.m */, 182 | C98ADE3011FF7D6A0071FF73 /* SBJsonParser.h */, 183 | C98ADE3111FF7D6A0071FF73 /* SBJsonParser.m */, 184 | C98ADE3211FF7D6A0071FF73 /* SBJsonWriter.h */, 185 | C98ADE3311FF7D6A0071FF73 /* SBJsonWriter.m */, 186 | ); 187 | path = JSON; 188 | sourceTree = ""; 189 | }; 190 | C98ADF2011FF996F0071FF73 /* Tests */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | C98ADF2211FF99A70071FF73 /* LogicTests.h */, 194 | C98ADF2311FF99A70071FF73 /* LogicTests.m */, 195 | ); 196 | name = Tests; 197 | sourceTree = ""; 198 | }; 199 | C98ADF2111FF99740071FF73 /* Core */ = { 200 | isa = PBXGroup; 201 | children = ( 202 | C98ADE4311FF7D7B0071FF73 /* MRTranslationOperation.h */, 203 | C98ADE4411FF7D7B0071FF73 /* MRTranslationOperation.m */, 204 | ); 205 | name = Core; 206 | sourceTree = ""; 207 | }; 208 | /* End PBXGroup section */ 209 | 210 | /* Begin PBXHeadersBuildPhase section */ 211 | 8DC2EF500486A6940098B216 /* Headers */ = { 212 | isa = PBXHeadersBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | C98ADCBE11FF70BC0071FF73 /* TranslationKit.h in Headers */, 216 | C98ADE3411FF7D6A0071FF73 /* JSON.h in Headers */, 217 | C98ADE3511FF7D6A0071FF73 /* NSObject+SBJSON.h in Headers */, 218 | C98ADE3711FF7D6A0071FF73 /* NSString+SBJSON.h in Headers */, 219 | C98ADE3911FF7D6A0071FF73 /* SBJSON.h in Headers */, 220 | C98ADE3B11FF7D6A0071FF73 /* SBJsonBase.h in Headers */, 221 | C98ADE3D11FF7D6A0071FF73 /* SBJsonParser.h in Headers */, 222 | C98ADE3F11FF7D6A0071FF73 /* SBJsonWriter.h in Headers */, 223 | C98ADE4511FF7D7B0071FF73 /* MRTranslationOperation.h in Headers */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | /* End PBXHeadersBuildPhase section */ 228 | 229 | /* Begin PBXNativeTarget section */ 230 | 8DC2EF4F0486A6940098B216 /* TranslationKit */ = { 231 | isa = PBXNativeTarget; 232 | buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "TranslationKit" */; 233 | buildPhases = ( 234 | 8DC2EF500486A6940098B216 /* Headers */, 235 | 8DC2EF520486A6940098B216 /* Resources */, 236 | 8DC2EF540486A6940098B216 /* Sources */, 237 | 8DC2EF560486A6940098B216 /* Frameworks */, 238 | ); 239 | buildRules = ( 240 | ); 241 | dependencies = ( 242 | ); 243 | name = TranslationKit; 244 | productInstallPath = "$(HOME)/Library/Frameworks"; 245 | productName = TranslationKit; 246 | productReference = 8DC2EF5B0486A6940098B216 /* TranslationKit.framework */; 247 | productType = "com.apple.product-type.framework"; 248 | }; 249 | C98ADF1A11FF99690071FF73 /* Tests */ = { 250 | isa = PBXNativeTarget; 251 | buildConfigurationList = C98ADF1F11FF99690071FF73 /* Build configuration list for PBXNativeTarget "Tests" */; 252 | buildPhases = ( 253 | C98ADF1611FF99690071FF73 /* Resources */, 254 | C98ADF1711FF99690071FF73 /* Sources */, 255 | C98ADF1811FF99690071FF73 /* Frameworks */, 256 | C98ADF1911FF99690071FF73 /* ShellScript */, 257 | ); 258 | buildRules = ( 259 | ); 260 | dependencies = ( 261 | C9E7FF011200A40000FCC6FB /* PBXTargetDependency */, 262 | ); 263 | name = Tests; 264 | productName = Tests; 265 | productReference = C98ADF1B11FF99690071FF73 /* Tests.octest */; 266 | productType = "com.apple.product-type.bundle"; 267 | }; 268 | /* End PBXNativeTarget section */ 269 | 270 | /* Begin PBXProject section */ 271 | 0867D690FE84028FC02AAC07 /* Project object */ = { 272 | isa = PBXProject; 273 | buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "TranslationKit" */; 274 | compatibilityVersion = "Xcode 3.1"; 275 | developmentRegion = English; 276 | hasScannedForEncodings = 1; 277 | knownRegions = ( 278 | en, 279 | ); 280 | mainGroup = 0867D691FE84028FC02AAC07 /* TranslationKit */; 281 | productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; 282 | projectDirPath = ""; 283 | projectRoot = ""; 284 | targets = ( 285 | 8DC2EF4F0486A6940098B216 /* TranslationKit */, 286 | C98ADF1A11FF99690071FF73 /* Tests */, 287 | ); 288 | }; 289 | /* End PBXProject section */ 290 | 291 | /* Begin PBXResourcesBuildPhase section */ 292 | 8DC2EF520486A6940098B216 /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | C98ADF1611FF99690071FF73 /* Resources */ = { 301 | isa = PBXResourcesBuildPhase; 302 | buildActionMask = 2147483647; 303 | files = ( 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | }; 307 | /* End PBXResourcesBuildPhase section */ 308 | 309 | /* Begin PBXShellScriptBuildPhase section */ 310 | C98ADF1911FF99690071FF73 /* ShellScript */ = { 311 | isa = PBXShellScriptBuildPhase; 312 | buildActionMask = 2147483647; 313 | files = ( 314 | ); 315 | inputPaths = ( 316 | ); 317 | outputPaths = ( 318 | ); 319 | runOnlyForDeploymentPostprocessing = 0; 320 | shellPath = /bin/sh; 321 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 322 | }; 323 | /* End PBXShellScriptBuildPhase section */ 324 | 325 | /* Begin PBXSourcesBuildPhase section */ 326 | 8DC2EF540486A6940098B216 /* Sources */ = { 327 | isa = PBXSourcesBuildPhase; 328 | buildActionMask = 2147483647; 329 | files = ( 330 | C98ADE3611FF7D6A0071FF73 /* NSObject+SBJSON.m in Sources */, 331 | C98ADE3811FF7D6A0071FF73 /* NSString+SBJSON.m in Sources */, 332 | C98ADE3A11FF7D6A0071FF73 /* SBJSON.m in Sources */, 333 | C98ADE3C11FF7D6A0071FF73 /* SBJsonBase.m in Sources */, 334 | C98ADE3E11FF7D6A0071FF73 /* SBJsonParser.m in Sources */, 335 | C98ADE4011FF7D6A0071FF73 /* SBJsonWriter.m in Sources */, 336 | C98ADE4611FF7D7B0071FF73 /* MRTranslationOperation.m in Sources */, 337 | ); 338 | runOnlyForDeploymentPostprocessing = 0; 339 | }; 340 | C98ADF1711FF99690071FF73 /* Sources */ = { 341 | isa = PBXSourcesBuildPhase; 342 | buildActionMask = 2147483647; 343 | files = ( 344 | C98ADF2411FF99A70071FF73 /* LogicTests.m in Sources */, 345 | ); 346 | runOnlyForDeploymentPostprocessing = 0; 347 | }; 348 | /* End PBXSourcesBuildPhase section */ 349 | 350 | /* Begin PBXTargetDependency section */ 351 | C9E7FF011200A40000FCC6FB /* PBXTargetDependency */ = { 352 | isa = PBXTargetDependency; 353 | target = 8DC2EF4F0486A6940098B216 /* TranslationKit */; 354 | targetProxy = C9E7FF001200A40000FCC6FB /* PBXContainerItemProxy */; 355 | }; 356 | /* End PBXTargetDependency section */ 357 | 358 | /* Begin PBXVariantGroup section */ 359 | 089C1666FE841158C02AAC07 /* InfoPlist.strings */ = { 360 | isa = PBXVariantGroup; 361 | children = ( 362 | 089C1667FE841158C02AAC07 /* English */, 363 | ); 364 | name = InfoPlist.strings; 365 | sourceTree = ""; 366 | }; 367 | /* End PBXVariantGroup section */ 368 | 369 | /* Begin XCBuildConfiguration section */ 370 | 1DEB91AE08733DA50010E9CD /* Debug */ = { 371 | isa = XCBuildConfiguration; 372 | buildSettings = { 373 | ALWAYS_SEARCH_USER_PATHS = NO; 374 | COPY_PHASE_STRIP = NO; 375 | DYLIB_COMPATIBILITY_VERSION = 1; 376 | DYLIB_CURRENT_VERSION = 1; 377 | FRAMEWORK_VERSION = A; 378 | GCC_DYNAMIC_NO_PIC = NO; 379 | GCC_ENABLE_FIX_AND_CONTINUE = YES; 380 | GCC_MODEL_TUNING = G5; 381 | GCC_OPTIMIZATION_LEVEL = 0; 382 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 383 | GCC_PREFIX_HEADER = TranslationKit_Prefix.pch; 384 | INFOPLIST_FILE = Info.plist; 385 | INSTALL_PATH = "@executable_path/../Frameworks"; 386 | PRODUCT_NAME = TranslationKit; 387 | WRAPPER_EXTENSION = framework; 388 | }; 389 | name = Debug; 390 | }; 391 | 1DEB91AF08733DA50010E9CD /* Release */ = { 392 | isa = XCBuildConfiguration; 393 | buildSettings = { 394 | ALWAYS_SEARCH_USER_PATHS = NO; 395 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 396 | DYLIB_COMPATIBILITY_VERSION = 1; 397 | DYLIB_CURRENT_VERSION = 1; 398 | FRAMEWORK_VERSION = A; 399 | GCC_MODEL_TUNING = G5; 400 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 401 | GCC_PREFIX_HEADER = TranslationKit_Prefix.pch; 402 | INFOPLIST_FILE = Info.plist; 403 | INSTALL_PATH = "@executable_path/../Frameworks"; 404 | PRODUCT_NAME = TranslationKit; 405 | WRAPPER_EXTENSION = framework; 406 | }; 407 | name = Release; 408 | }; 409 | 1DEB91B208733DA50010E9CD /* Debug */ = { 410 | isa = XCBuildConfiguration; 411 | buildSettings = { 412 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 413 | GCC_C_LANGUAGE_STANDARD = gnu99; 414 | GCC_ENABLE_OBJC_GC = supported; 415 | GCC_OPTIMIZATION_LEVEL = 0; 416 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 417 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 418 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 419 | GCC_WARN_UNUSED_VARIABLE = YES; 420 | ONLY_ACTIVE_ARCH = YES; 421 | PREBINDING = NO; 422 | RUN_CLANG_STATIC_ANALYZER = YES; 423 | SDKROOT = macosx; 424 | }; 425 | name = Debug; 426 | }; 427 | 1DEB91B308733DA50010E9CD /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 431 | GCC_C_LANGUAGE_STANDARD = gnu99; 432 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 433 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 434 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 435 | GCC_WARN_UNUSED_VARIABLE = YES; 436 | PREBINDING = NO; 437 | RUN_CLANG_STATIC_ANALYZER = YES; 438 | SDKROOT = macosx; 439 | }; 440 | name = Release; 441 | }; 442 | C98ADF1D11FF99690071FF73 /* Debug */ = { 443 | isa = XCBuildConfiguration; 444 | buildSettings = { 445 | ALWAYS_SEARCH_USER_PATHS = NO; 446 | COPY_PHASE_STRIP = NO; 447 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 448 | GCC_DYNAMIC_NO_PIC = NO; 449 | GCC_ENABLE_FIX_AND_CONTINUE = NO; 450 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 451 | GCC_MODEL_TUNING = G5; 452 | GCC_OPTIMIZATION_LEVEL = 0; 453 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 454 | GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Cocoa.framework/Headers/Cocoa.h"; 455 | INFOPLIST_FILE = "Tests-Info.plist"; 456 | INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles"; 457 | OTHER_LDFLAGS = ( 458 | "-framework", 459 | Cocoa, 460 | "-framework", 461 | SenTestingKit, 462 | ); 463 | PREBINDING = NO; 464 | PRODUCT_NAME = Tests; 465 | WRAPPER_EXTENSION = octest; 466 | }; 467 | name = Debug; 468 | }; 469 | C98ADF1E11FF99690071FF73 /* Release */ = { 470 | isa = XCBuildConfiguration; 471 | buildSettings = { 472 | ALWAYS_SEARCH_USER_PATHS = NO; 473 | COPY_PHASE_STRIP = YES; 474 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 475 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 476 | GCC_ENABLE_FIX_AND_CONTINUE = NO; 477 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 478 | GCC_MODEL_TUNING = G5; 479 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 480 | GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Cocoa.framework/Headers/Cocoa.h"; 481 | INFOPLIST_FILE = "Tests-Info.plist"; 482 | INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles"; 483 | OTHER_LDFLAGS = ( 484 | "-framework", 485 | Cocoa, 486 | "-framework", 487 | SenTestingKit, 488 | ); 489 | PREBINDING = NO; 490 | PRODUCT_NAME = Tests; 491 | WRAPPER_EXTENSION = octest; 492 | ZERO_LINK = NO; 493 | }; 494 | name = Release; 495 | }; 496 | /* End XCBuildConfiguration section */ 497 | 498 | /* Begin XCConfigurationList section */ 499 | 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "TranslationKit" */ = { 500 | isa = XCConfigurationList; 501 | buildConfigurations = ( 502 | 1DEB91AE08733DA50010E9CD /* Debug */, 503 | 1DEB91AF08733DA50010E9CD /* Release */, 504 | ); 505 | defaultConfigurationIsVisible = 0; 506 | defaultConfigurationName = Release; 507 | }; 508 | 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "TranslationKit" */ = { 509 | isa = XCConfigurationList; 510 | buildConfigurations = ( 511 | 1DEB91B208733DA50010E9CD /* Debug */, 512 | 1DEB91B308733DA50010E9CD /* Release */, 513 | ); 514 | defaultConfigurationIsVisible = 0; 515 | defaultConfigurationName = Release; 516 | }; 517 | C98ADF1F11FF99690071FF73 /* Build configuration list for PBXNativeTarget "Tests" */ = { 518 | isa = XCConfigurationList; 519 | buildConfigurations = ( 520 | C98ADF1D11FF99690071FF73 /* Debug */, 521 | C98ADF1E11FF99690071FF73 /* Release */, 522 | ); 523 | defaultConfigurationIsVisible = 0; 524 | defaultConfigurationName = Release; 525 | }; 526 | /* End XCConfigurationList section */ 527 | }; 528 | rootObject = 0867D690FE84028FC02AAC07 /* Project object */; 529 | } 530 | --------------------------------------------------------------------------------