├── .gitignore ├── .swift-version ├── CHANGELOG.md ├── Classes ├── NSObject+YAJL.h ├── NSObject+YAJL.m ├── YAJLDocument.h ├── YAJLDocument.m ├── YAJLGen.h ├── YAJLGen.m ├── YAJLParser.h └── YAJLParser.m ├── Info.plist ├── LICENSE ├── Package.swift ├── README.md ├── Tests-Info.plist ├── Tests ├── GHUnitTestMain.m ├── NSDataTest.m ├── NSObjectTest.m ├── NSStringTest.m ├── RunTests.sh ├── Samples │ ├── comments.json │ ├── document_streaming.json │ ├── error.json │ ├── error2.json │ ├── example.json │ ├── gen_expected1.json │ ├── gen_expected2.json │ ├── gen_expected_ignore_unknown1.json │ ├── gen_expected_plist1.json │ ├── object_expected_array.json │ ├── overflow.json │ ├── overflow2.json │ ├── overflow_longlong.json │ ├── overflow_longlong_macosx.json │ ├── sample.json │ ├── stream1.json │ ├── stream2.json │ ├── stream_array1.json │ ├── stream_array2.json │ ├── twitter.json │ └── twitter_snowflake.json ├── TwitterTest.m ├── YAJLDocumentDelegateTest.m ├── YAJLDocumentTest.m ├── YAJLGenTest.m ├── YAJLParserTest.m ├── YAJLTestCase.h └── YAJLTestCase.m ├── YAJL.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── YAJL Library.xcscheme ├── YAJLO.podspec └── yajl-2.1.0 ├── api ├── yajl_common.h ├── yajl_gen.h ├── yajl_parse.h ├── yajl_tree.h └── yajl_version.h ├── yajl.c ├── yajl_alloc.c ├── yajl_alloc.h ├── yajl_buf.c ├── yajl_buf.h ├── yajl_bytestack.h ├── yajl_encode.c ├── yajl_encode.h ├── yajl_gen.c ├── yajl_lex.c ├── yajl_lex.h ├── yajl_parser.c ├── yajl_parser.h ├── yajl_tree.c └── yajl_version.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | **/xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | *.xccheckout 19 | 20 | # OS X 21 | *.swp 22 | 23 | #AppCode 24 | .idea/workspace.xml 25 | .idea/tasks.xml 26 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | == 0.2.25 2 | 3 | - Fixing YAJL (iOS) build. 4 | 5 | == 0.2.22 6 | 7 | - Fixing YAJL (Mac OSX) build. 8 | 9 | == 0.2.21 10 | 11 | - Renaming categories to namespace them in case they are used externally. 12 | 13 | == 0.2.20 14 | 15 | - Added framework build for iPhone 16 | 17 | == 0.2.17 18 | 19 | - Updated to use yalj 1.0.9 (iPhone) 20 | 21 | == 0.2.16 22 | 23 | - Hudson (JUnit XML support) 24 | - Fix YAJL.h import 25 | - Updated to use yajl 1.0.9 26 | 27 | == 0.2.15 28 | 29 | - YAJLParserOptionsStrictPrecision option 30 | - Parsing as double on long long overflow, unless strict precision option 31 | 32 | == 0.2.14 33 | 34 | - Fixing build problem 35 | 36 | == 0.2.13 37 | 38 | - Using long long for non-decimal types (instead of always double). 39 | 40 | == 0.2.12 41 | 42 | - Fixing MacOSX build/install to use @rpath correctly 43 | - Defined error codes, and error userInfo key for value we errored on 44 | 45 | == 0.2.11 46 | 47 | - Fixed bug where yajl_JSONWithOptions:error: would ignore options. 48 | 49 | == 0.2.10 50 | 51 | - Gen options for ignoring unknown types and supporting PList types like NSData and NSDate 52 | - Changed default capacity in YAJLDocument for slightly better perf 53 | 54 | == 0.2.9 55 | 56 | - Enabling verbose errors in yajl 57 | 58 | == 0.2.8 59 | 60 | - Memory usage fix from wooster (autorelease to release) 61 | - Fixed memory leak when number parse error 62 | - Added default init methods for YAJLDocument and YAJLParser 63 | 64 | == 0.2.7 65 | 66 | - Changed yajl_encodeJSON to JSON for YAJLCoding protocol 67 | - Updating comments for YAJLCoding 68 | 69 | == 0.2.6 70 | 71 | - Supporting gen/parse from NSObject category (supports NSString, NSData and custom) 72 | - Including standard/optimized build for arm6/7 73 | - Include yajl_*.h api header files (iPhone) 74 | - 32/64 bit universal build (Mac OSX) 75 | 76 | == 0.2.5 77 | 78 | - Added YAJLGen wrapper for yajl_gen 79 | - Added streaming support to YAJLDocument 80 | - Added NSString category 81 | - Added NSObject category 82 | 83 | == 0.2.4 84 | 85 | - Using yajl_number callback since its more compliant (correctly handles large double values) 86 | - Changing YAJLParser API to allow for streaming data 87 | - Added test for overflow.json 88 | - Added test for insane sample.json 89 | 90 | == 0.2.3 91 | 92 | - Fixed memory leak in YAJLParser 93 | -------------------------------------------------------------------------------- /Classes/NSObject+YAJL.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+YAJL.h 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 7/23/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "YAJLGen.h" 31 | #import "YAJLParser.h" 32 | 33 | /*! 34 | Generate JSON string from NSArray, NSDictionary or custom object or parse JSON from NSString or custom object. 35 | 36 | Parse JSON: 37 | @code 38 | NSData *JSONData = [NSData dataWithContentsOfFile:@"example.json"]; 39 | NSArray *arrayFromData = [JSONData yajl_JSON]; 40 | 41 | NSString *JSONString = @"[\"Test\"]"; 42 | NSArray *arrayFromString = [JSONString yajl_JSON]; 43 | 44 | // With options and out error 45 | NSError *error = nil; 46 | NSArray *arrayFromString = [JSONString yajl_JSONWithOptions:YAJLParserOptionsAllowComments error:&error]; 47 | @endcode 48 | 49 | Generate JSON: 50 | @code 51 | NSDictionary *dict = [NSDictionary dictionaryWithObject:@"value" forKey:@"key"]; 52 | NSString *JSONString = [dict yajl_JSONString]; 53 | 54 | // Beautified with custon indent string 55 | NSArray *array = [NSArray arrayWithObjects:@"value1", @"value2", nil]; 56 | NSString *JSONString = [dict yajl_JSONStringWithOptions:YAJLGenOptionsBeautify indentString:@" "]; 57 | @endcode 58 | */ 59 | @interface NSObject(YAJL) 60 | 61 | #pragma mark Gen 62 | 63 | /*! 64 | Create JSON string from object. 65 | Supported objects include: NSArray, NSDictionary, NSNumber, NSString, NSNull 66 | To override JSON value to encode (or support custom objects), implement (id)JSON; See YAJLCoding in YAJLGen.h 67 | @throws YAJLGenInvalidObjectException If object is invalid 68 | @result JSON String 69 | */ 70 | @property (NS_NONATOMIC_IOSONLY, readonly, copy) NSString *yajl_JSONString; 71 | 72 | /*! 73 | Create JSON string from object. 74 | Supported objects include: NSArray, NSDictionary, NSNumber, NSString, NSNull 75 | To override JSON value to encode (or support custom objects), implement (id)JSON; See YAJLCoding in YAJLGen.h 76 | @throws YAJLGenInvalidObjectException If object is invalid 77 | @param options 78 | - YAJLGenOptionsNone: No options 79 | - YAJLGenOptionsBeautify: Beautifiy JSON output 80 | - YAJLGenOptionsIgnoreUnknownTypes: Ignore unknown types (will use null value) 81 | - YAJLGenOptionsIncludeUnsupportedTypes: Handle non-JSON types (including NSDate, NSData, NSURL) 82 | 83 | @param indentString 84 | @result JSON String 85 | */ 86 | - (NSString *)yajl_JSONStringWithOptions:(YAJLGenOptions)options indentString:(NSString *)indentString; 87 | 88 | 89 | #pragma mark Parsing 90 | 91 | /*! 92 | Parse JSON (NSString or NSData or dataUsingEncoding:). 93 | @result JSON object 94 | @throws YAJLParserException If a parse error occured 95 | @throws YAJLParsingUnsupportedException If not NSData or doesn't respond to dataUsingEncoding: 96 | 97 | @code 98 | NSString *JSONString = @"{'foo':['bar', true]}"; 99 | id JSONValue = [JSONString yajl_JSON]; 100 | 101 | NSData *JSONData = ...; 102 | id JSONValue = [JSONData yajl_JSON]; 103 | @endcode 104 | */ 105 | @property (NS_NONATOMIC_IOSONLY, readonly, strong) id yajl_JSON; 106 | 107 | /*! 108 | Parse JSON (NSString or NSData or dataUsingEncoding:) with out error. 109 | 110 | If an error occurs, the returned object will be the current state of the object when 111 | the error occurred. 112 | 113 | @param error Error to set if we failed to parse 114 | @result JSON object 115 | @throws YAJLParserException If a parse error occured 116 | @throws YAJLParsingUnsupportedException If not NSData or doesn't respond to dataUsingEncoding: 117 | 118 | @code 119 | NSString *JSONString = @"{'foo':['bar', true]}"; 120 | NSError *error = nil; 121 | [JSONString yajl_JSON:error]; 122 | if (error) ...; 123 | @endcode 124 | */ 125 | - (id)yajl_JSON:(NSError **)error; 126 | 127 | /*! 128 | Parse JSON (NSString or NSData or dataUsingEncoding:) with options and out error. 129 | 130 | If an error occurs, the returned object will be the current state of the object when 131 | the error occurred. 132 | 133 | @param options Parse options 134 | - YAJLParserOptionsNone: No options 135 | - YAJLParserOptionsAllowComments: Javascript style comments will be allowed in the input (both /&asterisk; &asterisk;/ and //) 136 | - YAJLParserOptionsCheckUTF8: Invalid UTF8 strings will cause a parse error 137 | - YAJLParserOptionsStrictPrecision: If YES will force strict precision and return integer overflow error 138 | 139 | @param error Error to set if we failed to parse 140 | @result JSON object 141 | @throws YAJLParserException If a parse error occured 142 | @throws YAJLParsingUnsupportedException If not NSData or doesn't respond to dataUsingEncoding: 143 | 144 | @code 145 | NSString *JSONString = @"{'foo':['bar', true]} // comment"; 146 | NSError *error = nil; 147 | [JSONString yajl_JSONWithOptions:YAJLParserOptionsAllowComments error:error]; 148 | if (error) ...; 149 | @endcode 150 | */ 151 | - (id)yajl_JSONWithOptions:(YAJLParserOptions)options error:(NSError **)error; 152 | 153 | @end 154 | 155 | -------------------------------------------------------------------------------- /Classes/NSObject+YAJL.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+YAJL.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 7/23/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "NSObject+YAJL.h" 31 | #import "YAJLGen.h" 32 | #import "YAJLDocument.h" 33 | 34 | @implementation NSObject(YAJL) 35 | 36 | #pragma mark Gen 37 | 38 | - (NSString *)yajl_JSONString { 39 | return [self yajl_JSONStringWithOptions:YAJLGenOptionsNone indentString:@" "]; 40 | } 41 | 42 | - (NSString *)yajl_JSONStringWithOptions:(YAJLGenOptions)options indentString:(NSString *)indentString { 43 | YAJLGen *gen = [[YAJLGen alloc] initWithGenOptions:options indentString:indentString]; 44 | [gen object:self]; 45 | return [gen buffer]; 46 | } 47 | 48 | #pragma mark Parsing 49 | 50 | - (id)yajl_JSON { 51 | NSError *error = nil; 52 | id JSON = [self yajl_JSON:&error]; 53 | if (error) [NSException raise:YAJLParserException format:error.localizedDescription, nil]; 54 | return JSON; 55 | } 56 | 57 | - (id)yajl_JSON:(NSError **)error { 58 | return [self yajl_JSONWithOptions:YAJLParserOptionsNone error:error]; 59 | } 60 | 61 | - (id)yajl_JSONWithOptions:(YAJLParserOptions)options error:(NSError **)error { 62 | NSData *data = nil; 63 | if ([self isKindOfClass:[NSData class]]) { 64 | data = (NSData *)self; 65 | } else if ([self respondsToSelector:@selector(dataUsingEncoding:)]) { 66 | data = [(id)self dataUsingEncoding:NSUTF8StringEncoding]; 67 | } else { 68 | [NSException raise:YAJLParsingUnsupportedException format:@"Object of type (%@) must implement dataUsingEncoding: to be parsed", [self class]]; 69 | } 70 | 71 | YAJLDocument *document = [[YAJLDocument alloc] initWithData:data parserOptions:options error:error]; 72 | return document.root; 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /Classes/YAJLDocument.h: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLDecoder.h 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 3/1/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | #include "YAJLParser.h" 32 | 33 | typedef NS_ENUM(unsigned int, YAJLDecoderCurrentType) { 34 | YAJLDecoderCurrentTypeNone, 35 | YAJLDecoderCurrentTypeArray, 36 | YAJLDecoderCurrentTypeDict 37 | }; 38 | 39 | extern NSInteger YAJLDocumentStackCapacity; 40 | 41 | @class YAJLDocument; 42 | 43 | /*! 44 | YAJLDocument delegate notified when objects are added. 45 | */ 46 | @protocol YAJLDocumentDelegate 47 | @optional 48 | /*! 49 | Did add dictionary. 50 | @param document Sender 51 | @param dict Dictionary that was added 52 | */ 53 | - (void)document:(YAJLDocument *)document didAddDictionary:(NSDictionary *)dict; 54 | 55 | /*! 56 | Did add array. 57 | @param document Sender 58 | @param array Array that was added 59 | */ 60 | - (void)document:(YAJLDocument *)document didAddArray:(NSArray *)array; 61 | 62 | /*! 63 | Did add object to array. 64 | @param document Sender 65 | @param object Object added 66 | @param array Array objct was added to 67 | */ 68 | - (void)document:(YAJLDocument *)document didAddObject:(id)object toArray:(NSArray *)array; 69 | 70 | /*! 71 | Did set object for key on dictionary. 72 | @param document Sender 73 | @param object Object that was set 74 | @param key Key 75 | @param dict Dictionary object was set for key on 76 | */ 77 | - (void)document:(YAJLDocument *)document didSetObject:(id)object forKey:(id)key inDictionary:(NSDictionary *)dict; 78 | @end 79 | 80 | /*! 81 | JSON document interface. 82 | 83 | @code 84 | NSData *data = [NSData dataWithContentsOfFile:@"example.json"]; 85 | NSError *error = nil; 86 | YAJLDocument *document = [[YAJLDocument alloc] initWithData:data parserOptions:YAJLParserOptionsNone error:&error]; 87 | // Access root element at document.root 88 | NSLog(@"Root: %@", document.root); 89 | @endcode 90 | 91 | Example for streaming: 92 | @code 93 | YAJLDocument *document = [[YAJLDocument alloc] init]; 94 | document.delegate = self; 95 | 96 | NSError *error = nil; 97 | [document parse:chunk1 error:error]; 98 | [document parse:chunk2 error:error]; 99 | 100 | // You can access root element at document.root 101 | NSLog(@"Root: %@", document.root); 102 | 103 | // Or via the YAJLDocumentDelegate delegate methods 104 | 105 | - (void)document:(YAJLDocument *)document didAddDictionary:(NSDictionary *)dict { } 106 | - (void)document:(YAJLDocument *)document didAddArray:(NSArray *)array { } 107 | - (void)document:(YAJLDocument *)document didAddObject:(id)object toArray:(NSArray *)array { } 108 | - (void)document:(YAJLDocument *)document didSetObject:(id)object forKey:(id)key inDictionary:(NSDictionary *)dict { } 109 | @endcode 110 | */ 111 | @interface YAJLDocument : NSObject 112 | 113 | @property (readonly, nonatomic) id root; //! The root element of the document, either NSArray or NSDictionary 114 | @property (readonly, nonatomic) YAJLParserStatus parserStatus; //! The current status of parsing 115 | @property (weak, nonatomic) id delegate; //! Delegate 116 | 117 | /*! 118 | Create document from data. 119 | @param data Data to parse 120 | @param parserOptions Parse options 121 | - YAJLParserOptionsNone: No options 122 | - YAJLParserOptionsAllowComments: Javascript style comments will be allowed in the input (both /&asterisk; &asterisk;/ and //) 123 | - YAJLParserOptionsCheckUTF8: Invalid UTF8 strings will cause a parse error 124 | - YAJLParserOptionsStrictPrecision: If YES will force strict precision and return integer overflow error 125 | @param error Error to set on failure 126 | */ 127 | - (instancetype)initWithData:(NSData *)data parserOptions:(YAJLParserOptions)parserOptions error:(NSError **)error; 128 | 129 | /*! 130 | Create document from data. 131 | @param data Data to parse 132 | @param parserOptions Parse options 133 | - YAJLParserOptionsNone: No options 134 | - YAJLParserOptionsAllowComments: Javascript style comments will be allowed in the input (both /&asterisk; &asterisk;/ and //) 135 | - YAJLParserOptionsCheckUTF8: Invalid UTF8 strings will cause a parse error 136 | - YAJLParserOptionsStrictPrecision: If YES will force strict precision and return integer overflow error 137 | @param capacity Initial capacity for NSArray and NSDictionary objects (Defaults to 20) 138 | @param error Error to set on failure 139 | */ 140 | - (instancetype)initWithData:(NSData *)data parserOptions:(YAJLParserOptions)parserOptions capacity:(NSInteger)capacity error:(NSError **)error; 141 | 142 | /*! 143 | Create empty document with parser options. 144 | @param parserOptions Parse options 145 | - YAJLParserOptionsNone: No options 146 | - YAJLParserOptionsAllowComments: Javascript style comments will be allowed in the input (both /&asterisk; &asterisk;/ and //) 147 | - YAJLParserOptionsCheckUTF8: Invalid UTF8 strings will cause a parse error 148 | - YAJLParserOptionsStrictPrecision: If YES will force strict precision and return integer overflow error 149 | */ 150 | - (instancetype)initWithParserOptions:(YAJLParserOptions)parserOptions; 151 | 152 | /*! 153 | Create empty document with parser options. 154 | @param parserOptions Parse options 155 | - YAJLParserOptionsNone: No options 156 | - YAJLParserOptionsAllowComments: Javascript style comments will be allowed in the input (both /&asterisk; &asterisk;/ and //) 157 | - YAJLParserOptionsCheckUTF8: Invalid UTF8 strings will cause a parse error 158 | - YAJLParserOptionsStrictPrecision: If YES will force strict precision and return integer overflow error 159 | @param capacity Initial capacity for NSArray and NSDictionary objects (Defaults to 20) 160 | */ 161 | - (instancetype)initWithParserOptions:(YAJLParserOptions)parserOptions capacity:(NSInteger)capacity NS_DESIGNATED_INITIALIZER; 162 | 163 | /*! 164 | Parse data. 165 | @param data Data to parse 166 | @param error Out error to set on failure 167 | @result Parser status 168 | - YAJLParserStatusNone: No status 169 | - YAJLParserStatusOK: Parsed OK 170 | - YAJLParserStatusInsufficientData: There was insufficient data 171 | - YAJLParserStatusError: Parser errored 172 | */ 173 | - (YAJLParserStatus)parse:(NSData *)data error:(NSError **)error; 174 | 175 | @end 176 | -------------------------------------------------------------------------------- /Classes/YAJLDocument.m: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLDocument.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 3/1/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | #import "YAJLDocument.h" 32 | 33 | @interface YAJLDocument () 34 | 35 | @property id root; // NSArray or NSDictionary 36 | @property YAJLParser *parser; 37 | 38 | @property (weak) NSMutableDictionary *dict; // if map in progress, points to the current map 39 | @property (weak) NSMutableArray *array; // If array in progress, points the current array 40 | @property (weak) NSString *key; // If map in progress, points to current key 41 | 42 | @property NSMutableArray *stack; 43 | @property NSMutableArray *keyStack; 44 | 45 | @property YAJLDecoderCurrentType currentType; 46 | 47 | @property YAJLParserStatus parserStatus; 48 | 49 | - (void)_pop; 50 | - (void)_popKey; 51 | @end 52 | 53 | NSInteger YAJLDocumentStackCapacity = 20; 54 | 55 | @implementation YAJLDocument 56 | 57 | - (instancetype)init { 58 | return [self initWithParserOptions:0]; 59 | } 60 | 61 | - (instancetype)initWithParserOptions:(YAJLParserOptions)parserOptions { 62 | return [self initWithParserOptions:parserOptions capacity:YAJLDocumentStackCapacity]; 63 | } 64 | 65 | - (instancetype)initWithParserOptions:(YAJLParserOptions)parserOptions capacity:(NSInteger)capacity { 66 | if ((self = [super init])) { 67 | _stack = [[NSMutableArray alloc] initWithCapacity:YAJLDocumentStackCapacity]; 68 | _keyStack = [[NSMutableArray alloc] initWithCapacity:YAJLDocumentStackCapacity]; 69 | _parserStatus = YAJLParserStatusNone; 70 | _parser = [[YAJLParser alloc] initWithParserOptions:parserOptions]; 71 | _parser.delegate = self; 72 | } 73 | return self; 74 | } 75 | 76 | - (instancetype)initWithData:(NSData *)data parserOptions:(YAJLParserOptions)parserOptions error:(NSError **)error { 77 | return [self initWithData:data parserOptions:parserOptions capacity:YAJLDocumentStackCapacity error:error]; 78 | } 79 | 80 | - (instancetype)initWithData:(NSData *)data parserOptions:(YAJLParserOptions)parserOptions capacity:(NSInteger)capacity error:(NSError **)error { 81 | if ((self = [self initWithParserOptions:parserOptions capacity:capacity])) { 82 | [self parse:data error:error]; 83 | } 84 | return self; 85 | } 86 | 87 | - (YAJLParserStatus)parse:(NSData *)data error:(NSError **)error { 88 | _parserStatus = [_parser parse:data]; 89 | if (error) *error = _parser.parserError; 90 | return _parserStatus; 91 | } 92 | 93 | #pragma mark Delegates 94 | 95 | - (void)parser:(YAJLParser *)parser didAdd:(id)value { 96 | switch (_currentType) { 97 | case YAJLDecoderCurrentTypeArray: 98 | [_array addObject:value]; 99 | if ([_delegate respondsToSelector:@selector(document:didAddObject:toArray:)]) 100 | [_delegate document:self didAddObject:value toArray:_array]; 101 | break; 102 | case YAJLDecoderCurrentTypeDict: 103 | NSParameterAssert(_key); 104 | if (value) _dict[_key] = value; 105 | if ([_delegate respondsToSelector:@selector(document:didSetObject:forKey:inDictionary:)]) 106 | [_delegate document:self didSetObject:value forKey:_key inDictionary:_dict]; 107 | [self _popKey]; 108 | break; 109 | default: 110 | break; 111 | } 112 | } 113 | 114 | - (void)parser:(YAJLParser *)parser didMapKey:(NSString *)key { 115 | _key = key; 116 | [_keyStack addObject:_key]; // Push 117 | } 118 | 119 | - (void)_popKey { 120 | _key = nil; 121 | [_keyStack removeLastObject]; // Pop 122 | if (_keyStack.count > 0) 123 | _key = _keyStack[_keyStack.count-1]; 124 | } 125 | 126 | - (void)parserDidStartDictionary:(YAJLParser *)parser { 127 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:YAJLDocumentStackCapacity]; 128 | if (!_root) _root = dict; 129 | [_stack addObject:dict]; // Push 130 | _dict = dict; 131 | _currentType = YAJLDecoderCurrentTypeDict; 132 | } 133 | 134 | - (void)parserDidEndDictionary:(YAJLParser *)parser { 135 | id value = _stack[_stack.count-1]; 136 | NSDictionary *dict = _dict; 137 | [self _pop]; 138 | [self parser:parser didAdd:value]; 139 | if ([_delegate respondsToSelector:@selector(document:didAddDictionary:)]) 140 | [_delegate document:self didAddDictionary:dict]; 141 | } 142 | 143 | - (void)parserDidStartArray:(YAJLParser *)parser { 144 | NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:YAJLDocumentStackCapacity]; 145 | if (!_root) _root = array; 146 | [_stack addObject:array]; // Push 147 | _array = array; 148 | _currentType = YAJLDecoderCurrentTypeArray; 149 | } 150 | 151 | - (void)parserDidEndArray:(YAJLParser *)parser { 152 | id value = _stack[_stack.count-1]; 153 | NSArray *array = _array; 154 | [self _pop]; 155 | [self parser:parser didAdd:value]; 156 | if ([_delegate respondsToSelector:@selector(document:didAddArray:)]) 157 | [_delegate document:self didAddArray:array]; 158 | } 159 | 160 | - (void)_pop { 161 | [_stack removeLastObject]; 162 | _array = nil; 163 | _dict = nil; 164 | _currentType = YAJLDecoderCurrentTypeNone; 165 | 166 | id value = nil; 167 | if (_stack.count > 0) value = _stack[_stack.count-1]; 168 | if ([value isKindOfClass:[NSArray class]]) { 169 | _array = (NSMutableArray *)value; 170 | _currentType = YAJLDecoderCurrentTypeArray; 171 | } else if ([value isKindOfClass:[NSDictionary class]]) { 172 | _dict = (NSMutableDictionary *)value; 173 | _currentType = YAJLDecoderCurrentTypeDict; 174 | } 175 | } 176 | 177 | @end 178 | -------------------------------------------------------------------------------- /Classes/YAJLGen.h: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLGen.h 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 7/19/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | @import Foundation; 31 | 32 | 33 | extern NSString *const YAJLGenInvalidObjectException; //! Exception type if we encounter invalid object 34 | 35 | //! JSON generate options 36 | typedef NS_ENUM(NSUInteger, YAJLGenOptions) { 37 | YAJLGenOptionsNone = 0, //!< No options 38 | YAJLGenOptionsBeautify = 1 << 0, //!< Beautifiy JSON output 39 | YAJLGenOptionsIgnoreUnknownTypes = 1 << 1, //!< Ignore unknown types (will use null value) 40 | YAJLGenOptionsIncludeUnsupportedTypes = 1 << 2, //!< Handle non-JSON types (including NSDate, NSData, NSURL) 41 | }; 42 | 43 | /*! 44 | YAJL JSON string generator. 45 | Supports the following types: 46 | - NSArray 47 | - NSDictionary 48 | - NSString 49 | - NSNumber 50 | - NSNull 51 | 52 | We also support the following types (if using YAJLGenOptionsIncludeUnsupportedTypes option), 53 | by converting to JSON supported types: 54 | - NSDate: number representing number of milliseconds since (1970) epoch 55 | - NSData: Base64 encoded string 56 | - NSURL: URL (absolute) string 57 | */ 58 | @interface YAJLGen : NSObject 59 | 60 | /*! 61 | JSON generator with options. 62 | @param genOptions Generate options 63 | - YAJLGenOptionsNone: No options 64 | - YAJLGenOptionsBeautify: Beautifiy JSON output 65 | - YAJLGenOptionsIgnoreUnknownTypes: Ignore unknown types (will use null value) 66 | - YAJLGenOptionsIncludeUnsupportedTypes: Handle non-JSON types (including NSDate, NSData, NSURL) 67 | 68 | @param indentString String for indentation 69 | */ 70 | - (instancetype)initWithGenOptions:(YAJLGenOptions)genOptions indentString:(NSString *)indentString NS_DESIGNATED_INITIALIZER; 71 | 72 | /*! 73 | Write JSON for object to buffer. 74 | @param obj Supported or custom object 75 | */ 76 | - (void)object:(id)obj; 77 | 78 | /*! 79 | Write null value to buffer. 80 | */ 81 | - (void)null; 82 | 83 | /*! 84 | Write bool value to buffer. 85 | @param b Output true or false 86 | */ 87 | - (void)bool:(BOOL)b; 88 | 89 | /*! 90 | Write numeric value to buffer. 91 | @param number Numeric value 92 | */ 93 | - (void)number:(NSNumber *)number; 94 | 95 | /*! 96 | Write string value to buffer. 97 | @param s String value 98 | */ 99 | - (void)string:(NSString *)s; 100 | 101 | /*! 102 | Write dictionary start ('{') to buffer. 103 | */ 104 | - (void)startDictionary; 105 | 106 | /*! 107 | Write dictionary end ('}') to buffer. 108 | */ 109 | - (void)endDictionary; 110 | 111 | /*! 112 | Write array start ('[') to buffer. 113 | */ 114 | - (void)startArray; 115 | 116 | /*! 117 | Write array end (']') to buffer. 118 | */ 119 | - (void)endArray; 120 | 121 | /*! 122 | Clear JSON buffer. 123 | */ 124 | - (void)clear; 125 | 126 | /*! 127 | Get current JSON buffer. 128 | */ 129 | @property (NS_NONATOMIC_IOSONLY, readonly, copy) NSString *buffer; 130 | 131 | @end 132 | 133 | 134 | /*! 135 | Custom objects can support manual JSON encoding. 136 | 137 | @code 138 | @interface CustomObject : NSObject 139 | @end 140 | 141 | @implementation CustomObject 142 | 143 | - (id)JSON { 144 | return [NSArray arrayWithObject:[NSNumber numberWithInteger:1]]; 145 | } 146 | 147 | @end 148 | @endcode 149 | 150 | And then: 151 | 152 | @code 153 | CustomObject *customObject = [[CustomObject alloc] init]; 154 | NSString *JSONString = [customObject yajl_JSON]; 155 | // JSONString == "[1]"; 156 | @endcode 157 | */ 158 | @protocol YAJLCoding 159 | 160 | /*! 161 | Provide custom and/or encodable object to parse to JSON string. 162 | @result Object encodable as JSON such as NSDictionary, NSArray, etc 163 | */ 164 | @property (NS_NONATOMIC_IOSONLY, readonly, strong) id JSON; 165 | 166 | @end 167 | -------------------------------------------------------------------------------- /Classes/YAJLGen.m: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLGen.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 7/19/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "YAJLGen.h" 31 | #import "yajl_gen.h" 32 | 33 | NSString *const YAJLGenInvalidObjectException = @"YAJLGenInvalidObjectException"; 34 | 35 | @interface YAJLGen () 36 | @property yajl_gen gen; 37 | @property YAJLGenOptions genOptions; 38 | @end 39 | 40 | @implementation YAJLGen 41 | 42 | - (instancetype)init { 43 | return [self initWithGenOptions:YAJLGenOptionsNone indentString:@""]; 44 | } 45 | 46 | - (instancetype)initWithGenOptions:(YAJLGenOptions)genOptions indentString:(NSString *)indentString { 47 | if ((self = [super init])) { 48 | _genOptions = genOptions; 49 | 50 | _gen = yajl_gen_alloc(NULL); 51 | 52 | yajl_gen_config(_gen, yajl_gen_beautify, (genOptions & YAJLGenOptionsBeautify) ? 1 : 0); 53 | yajl_gen_config(_gen, yajl_gen_indent_string, (indentString ?: @"").UTF8String); 54 | } 55 | return self; 56 | } 57 | 58 | - (void)dealloc { 59 | if (_gen != NULL) yajl_gen_free(_gen); 60 | } 61 | 62 | - (void)object:(id)obj { 63 | if ([obj respondsToSelector:@selector(JSON)]) { 64 | return [self object:[obj JSON]]; 65 | } else if ([obj isKindOfClass:[NSArray class]]) { 66 | [self startArray]; 67 | for(id element in obj) 68 | [self object:element]; 69 | [self endArray]; 70 | } else if ([obj isKindOfClass:[NSDictionary class]]) { 71 | [self startDictionary]; 72 | for(id key in obj) { 73 | [self object:key]; 74 | [self object:obj[key]]; 75 | } 76 | [self endDictionary]; 77 | } else if ([obj isKindOfClass:[NSNumber class]]) { 78 | if ('c' != *[obj objCType]) { 79 | [self number:obj]; 80 | } else { 81 | [self bool:[obj boolValue]]; 82 | } 83 | } else if ([obj isKindOfClass:[NSString class]]) { 84 | [self string:obj]; 85 | } else if ([obj isKindOfClass:[NSNull class]]) { 86 | [self null]; 87 | } else { 88 | 89 | BOOL unknownType = NO; 90 | if (_genOptions & YAJLGenOptionsIncludeUnsupportedTypes) { 91 | // Begin with support for non-JSON representable (PList) types 92 | if ([obj isKindOfClass:[NSDate class]]) { 93 | [self number:[NSNumber numberWithLongLong:round([obj timeIntervalSince1970] * 1000)]]; 94 | } else if ([obj isKindOfClass:[NSData class]]) { 95 | [self string:[(NSData*)obj base64EncodedStringWithOptions:0]]; 96 | } else if ([obj isKindOfClass:[NSURL class]]) { 97 | [self string:[obj absoluteString]]; 98 | } else { 99 | unknownType = YES; 100 | } 101 | } else { 102 | unknownType = YES; 103 | } 104 | 105 | // If we didn't handle special PList types 106 | if (unknownType) { 107 | if (!(_genOptions & YAJLGenOptionsIgnoreUnknownTypes)) { 108 | [NSException raise:YAJLGenInvalidObjectException format:@"Unknown object type: %@ (%@)", [obj class], obj]; 109 | } else { 110 | [self null]; // Use null value for unknown type if we are ignoring 111 | } 112 | } 113 | } 114 | } 115 | 116 | - (void)null { 117 | yajl_gen_null(_gen); 118 | } 119 | 120 | - (void)bool:(BOOL)b { 121 | yajl_gen_bool(_gen, b); 122 | } 123 | 124 | - (void)number:(NSNumber *)number { 125 | if ([number isEqualToNumber:[NSDecimalNumber notANumber]]) { 126 | yajl_gen_null(_gen); 127 | } else { 128 | NSString *s = number.stringValue; 129 | NSUInteger length = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 130 | const char *c = s.UTF8String; 131 | yajl_gen_number(_gen, c, (unsigned int) length); 132 | } 133 | } 134 | 135 | - (void)string:(NSString *)s { 136 | NSUInteger length = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 137 | const unsigned char *c = (const unsigned char *)s.UTF8String; 138 | yajl_gen_string(_gen, c, (unsigned int) length); 139 | } 140 | 141 | - (void)startDictionary { 142 | yajl_gen_map_open(_gen); 143 | } 144 | 145 | - (void)endDictionary { 146 | yajl_gen_map_close(_gen); 147 | } 148 | 149 | - (void)startArray { 150 | yajl_gen_array_open(_gen); 151 | } 152 | 153 | - (void)endArray { 154 | yajl_gen_array_close(_gen); 155 | } 156 | 157 | - (void)clear { 158 | yajl_gen_clear(_gen); 159 | } 160 | 161 | - (NSString *)buffer { 162 | const unsigned char *buf; 163 | size_t len; 164 | yajl_gen_get_buf(_gen, &buf, &len); 165 | NSString *s = @((const char*)buf); 166 | return s; 167 | } 168 | 169 | @end 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /Classes/YAJLParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLParser.h 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 6/14/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | @import Foundation; 31 | 32 | 33 | extern NSString *const YAJLErrorDomain; //! Error domain for YAJL 34 | extern NSString *const YAJLParserException; //! Generic parse exception 35 | extern NSString *const YAJLParsingUnsupportedException; //! Parsing unsupported exception 36 | 37 | extern NSString *const YAJLParserValueKey; //! Key in NSError userInfo for value we errored on 38 | 39 | //! Parser error codes 40 | typedef NS_ENUM(NSInteger, YAJLParserErrorCode) { 41 | YAJLParserErrorCodeAllocError = -1000, //!< Alloc error 42 | YAJLParserErrorCodeDoubleOverflow = -1001, //!< Double overflow 43 | YAJLParserErrorCodeIntegerOverflow = -1002 //!< Integer overflow 44 | }; 45 | 46 | //! Parser options 47 | typedef NS_ENUM(NSUInteger, YAJLParserOptions) { 48 | YAJLParserOptionsNone = 0, //!< No options 49 | YAJLParserOptionsAllowComments = 1 << 0, //!< Javascript style comments will be allowed in the input (both /&asterisk; &asterisk;/ and //) 50 | YAJLParserOptionsCheckUTF8 = 1 << 1, //!< Invalid UTF8 strings will cause a parse error 51 | YAJLParserOptionsStrictPrecision = 1 << 2, //!< If YES will force strict precision and return integer overflow error 52 | }; 53 | 54 | //! Parser status 55 | typedef NS_ENUM(NSUInteger, YAJLParserStatus) { 56 | YAJLParserStatusNone = 0, //!< No status 57 | YAJLParserStatusOK = 1, //!< Parsed OK 58 | YAJLParserStatusError = 3 //!< Parser errored 59 | }; 60 | 61 | 62 | @class YAJLParser; 63 | 64 | /*! 65 | Delegate for YAJL JSON parser. 66 | */ 67 | @protocol YAJLParserDelegate 68 | 69 | /*! 70 | Parser did start dictionary. 71 | @param parser Sender 72 | */ 73 | - (void)parserDidStartDictionary:(YAJLParser *)parser; 74 | 75 | /*! 76 | Parser did end dictionary. 77 | @param parser Sender 78 | */ 79 | - (void)parserDidEndDictionary:(YAJLParser *)parser; 80 | 81 | /*! 82 | Parser did start array. 83 | @param parser Sender 84 | */ 85 | - (void)parserDidStartArray:(YAJLParser *)parser; 86 | 87 | /*! 88 | Parser did end array. 89 | @param parser Sender 90 | */ 91 | - (void)parserDidEndArray:(YAJLParser *)parser; 92 | 93 | /*! 94 | Parser did map key. 95 | @param parser Sender 96 | @param key Key that was mapped 97 | */ 98 | - (void)parser:(YAJLParser *)parser didMapKey:(NSString *)key; 99 | 100 | /*! 101 | Did add value. 102 | @param parser Sender 103 | @param value Value of type NSNull, NSString or NSNumber 104 | */ 105 | - (void)parser:(YAJLParser *)parser didAdd:(id)value; 106 | 107 | @end 108 | 109 | /*! 110 | JSON parser. 111 | 112 | @code 113 | NSData *data = [NSData dataWithContentsOfFile:@"example.json"]; 114 | 115 | YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:YAJLParserOptionsAllowComments]; 116 | parser.delegate = self; 117 | [parser parse:data]; 118 | if (parser.parserError) { 119 | NSLog(@"Error:\n%@", parser.parserError); 120 | } 121 | 122 | parser.delegate = nil; 123 | 124 | // Include delegate methods from YAJLParserDelegate 125 | - (void)parserDidStartDictionary:(YAJLParser *)parser { } 126 | - (void)parserDidEndDictionary:(YAJLParser *)parser { } 127 | 128 | - (void)parserDidStartArray:(YAJLParser *)parser { } 129 | - (void)parserDidEndArray:(YAJLParser *)parser { } 130 | 131 | - (void)parser:(YAJLParser *)parser didMapKey:(NSString *)key { } 132 | - (void)parser:(YAJLParser *)parser didAdd:(id)value { } 133 | @endcode 134 | */ 135 | @interface YAJLParser : NSObject 136 | 137 | @property (weak, nonatomic) id delegate; 138 | @property (readonly, strong, nonatomic) NSError *parserError; 139 | @property (readonly, nonatomic) YAJLParserOptions parserOptions; 140 | @property (readonly, nonatomic) unsigned int bytesConsumed; 141 | 142 | /*! 143 | Create parser with data and options. 144 | @param parserOptions Parser options 145 | - YAJLParserOptionsNone: No options 146 | - YAJLParserOptionsAllowComments: Javascript style comments will be allowed in the input (both /&asterisk; &asterisk;/ and //) 147 | - YAJLParserOptionsCheckUTF8: Invalid UTF8 strings will cause a parse error 148 | - YAJLParserOptionsStrictPrecision: If YES will force strict precision and return integer overflow error 149 | */ 150 | - (instancetype)initWithParserOptions:(YAJLParserOptions)parserOptions NS_DESIGNATED_INITIALIZER; 151 | 152 | /*! 153 | Parse data. 154 | 155 | If streaming, you can call parse multiple times as long as 156 | previous calls return YAJLParserStatusInsufficientData. 157 | 158 | @param data 159 | @result Parser status 160 | - YAJLParserStatusNone: No status 161 | - YAJLParserStatusOK: Parsed OK 162 | - YAJLParserStatusInsufficientData: There was insufficient data 163 | - YAJLParserStatusError: Parser errored 164 | */ 165 | - (YAJLParserStatus)parse:(NSData *)data; 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /Classes/YAJLParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLParser.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 6/14/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | #import "YAJLParser.h" 32 | #import "yajl_parse.h" 33 | 34 | NSString *const YAJLErrorDomain = @"YAJLErrorDomain"; 35 | NSString *const YAJLParserException = @"YAJLParserException"; 36 | NSString *const YAJLParsingUnsupportedException = @"YAJLParsingUnsupportedException"; 37 | 38 | NSString *const YAJLParserValueKey = @"YAJLParserValueKey"; 39 | 40 | @interface YAJLParser () 41 | @property (strong, nonatomic) NSError *parserError; 42 | @end 43 | 44 | //! @internal 45 | 46 | @interface YAJLParser () 47 | @property yajl_handle handle; 48 | 49 | - (void)_add:(id)value; 50 | - (void)_mapKey:(NSString *)key; 51 | 52 | - (void)_startDictionary; 53 | - (void)_endDictionary; 54 | 55 | - (void)_startArray; 56 | - (void)_endArray; 57 | 58 | - (NSError *)_errorForStatus:(NSInteger)code message:(NSString *)message value:(NSString *)value; 59 | - (void)_cancelWithErrorForStatus:(NSInteger)code message:(NSString *)message value:(NSString *)value; 60 | @end 61 | 62 | //! @endinternal 63 | 64 | 65 | @implementation YAJLParser 66 | 67 | - (instancetype)init { 68 | return [self initWithParserOptions:0]; 69 | } 70 | 71 | - (instancetype)initWithParserOptions:(YAJLParserOptions)parserOptions { 72 | if ((self = [super init])) { 73 | _parserOptions = parserOptions; 74 | } 75 | return self; 76 | } 77 | 78 | - (void)dealloc { 79 | if (_handle != NULL) { 80 | yajl_free(_handle); 81 | _handle = NULL; 82 | } 83 | 84 | } 85 | 86 | #pragma mark Error Helpers 87 | 88 | - (NSError *)_errorForStatus:(NSInteger)code message:(NSString *)message value:(NSString *)value { 89 | NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObject:message forKey:NSLocalizedDescriptionKey]; 90 | if (value) userInfo[YAJLParserValueKey] = value; 91 | return [NSError errorWithDomain:YAJLErrorDomain code:code userInfo:userInfo]; 92 | } 93 | 94 | - (void)_cancelWithErrorForStatus:(NSInteger)code message:(NSString *)message value:(NSString *)value { 95 | self.parserError = [self _errorForStatus:code message:message value:value]; 96 | } 97 | 98 | #pragma mark YAJL Callbacks 99 | 100 | int yajl_null(void *ctx) { 101 | [(__bridge id)ctx _add:[NSNull null]]; 102 | return 1; 103 | } 104 | 105 | int yajl_boolean(void *ctx, int boolVal) { 106 | NSNumber *number = [[NSNumber alloc] initWithBool:(BOOL)boolVal]; 107 | [(__bridge id)ctx _add:number]; 108 | return 1; 109 | } 110 | 111 | // Instead of using yajl_integer, and yajl_double we use yajl_number and parse 112 | // as double (or long long); This is to be more compliant since Javascript numbers are represented 113 | // as double precision floating point, though JSON spec doesn't define a max value 114 | // and is up to the parser? 115 | 116 | //int yajl_integer(void *ctx, long integerVal) { 117 | // [(id)ctx _add:[NSNumber numberWithLong:integerVal]]; 118 | // return 1; 119 | //} 120 | // 121 | //int yajl_double(void *ctx, double doubleVal) { 122 | // [(id)ctx _add:[NSNumber numberWithDouble:doubleVal]]; 123 | // return 1; 124 | //} 125 | 126 | int ParseDouble(void *ctx, const char *buf, const char *numberVal, size_t numberLen) { 127 | double d = strtod((char *)buf, NULL); 128 | if ((d == HUGE_VAL || d == -HUGE_VAL) && errno == ERANGE) { 129 | NSString *s = [[NSString alloc] initWithBytes:numberVal length:numberLen encoding:NSUTF8StringEncoding]; 130 | [(__bridge id)ctx _cancelWithErrorForStatus:YAJLParserErrorCodeDoubleOverflow message:[NSString stringWithFormat:@"double overflow on '%@'", s] value:s]; 131 | return 0; 132 | } 133 | NSNumber *number = [[NSNumber alloc] initWithDouble:d]; 134 | [(__bridge id)ctx _add:number]; 135 | return 1; 136 | } 137 | 138 | int yajl_number(void *ctx, const char *numberVal, size_t numberLen) { 139 | char buf[numberLen+1]; 140 | memcpy(buf, numberVal, numberLen); 141 | buf[numberLen] = 0; 142 | 143 | if (memchr(numberVal, '.', numberLen) || memchr(numberVal, 'e', numberLen) || memchr(numberVal, 'E', numberLen)) { 144 | return ParseDouble(ctx, buf, numberVal, numberLen); 145 | } else { 146 | long long i = strtoll((const char *) buf, NULL, 10); 147 | if ((i == LLONG_MIN || i == LLONG_MAX) && errno == ERANGE) { 148 | if (([(__bridge id)ctx parserOptions] & YAJLParserOptionsStrictPrecision) == YAJLParserOptionsStrictPrecision) { 149 | NSString *s = [[NSString alloc] initWithBytes:numberVal length:numberLen encoding:NSUTF8StringEncoding]; 150 | [(__bridge id)ctx _cancelWithErrorForStatus:YAJLParserErrorCodeIntegerOverflow message:[NSString stringWithFormat:@"integer overflow on '%@'", s] value:s]; 151 | return 0; 152 | } else { 153 | // If we integer overflow lets try double precision for HUGE_VAL > double > LLONG_MAX 154 | return ParseDouble(ctx, buf, numberVal, numberLen); 155 | } 156 | } 157 | NSNumber *number = [[NSNumber alloc] initWithLongLong:i]; 158 | [(__bridge id)ctx _add:number]; 159 | } 160 | 161 | return 1; 162 | } 163 | 164 | int yajl_string(void *ctx, const unsigned char *stringVal, size_t stringLen) { 165 | NSString *s = [[NSString alloc] initWithBytes:stringVal length:stringLen encoding:NSUTF8StringEncoding]; 166 | [(__bridge id)ctx _add:s]; 167 | return 1; 168 | } 169 | 170 | int yajl_map_key(void *ctx, const unsigned char *stringVal, size_t stringLen) { 171 | NSString *s = [[NSString alloc] initWithBytes:stringVal length:stringLen encoding:NSUTF8StringEncoding]; 172 | [(__bridge id)ctx _mapKey:s]; 173 | return 1; 174 | } 175 | 176 | int yajl_start_map(void *ctx) { 177 | [(__bridge id)ctx _startDictionary]; 178 | return 1; 179 | } 180 | 181 | int yajl_end_map(void *ctx) { 182 | [(__bridge id)ctx _endDictionary]; 183 | return 1; 184 | } 185 | 186 | int yajl_start_array(void *ctx) { 187 | [(__bridge id)ctx _startArray]; 188 | return 1; 189 | } 190 | 191 | int yajl_end_array(void *ctx) { 192 | [(__bridge id)ctx _endArray]; 193 | return 1; 194 | } 195 | 196 | static yajl_callbacks callbacks = { 197 | yajl_null, 198 | yajl_boolean, 199 | NULL, // yajl_integer (using yajl_number) 200 | NULL, // yajl_double (using yajl_number) 201 | yajl_number, 202 | yajl_string, 203 | yajl_start_map, 204 | yajl_map_key, 205 | yajl_end_map, 206 | yajl_start_array, 207 | yajl_end_array 208 | }; 209 | 210 | #pragma mark - 211 | 212 | //! @internal 213 | 214 | - (void)_add:(id)value { 215 | [_delegate parser:self didAdd:value]; 216 | } 217 | 218 | - (void)_mapKey:(NSString *)key { 219 | [_delegate parser:self didMapKey:key]; 220 | } 221 | 222 | - (void)_startDictionary { 223 | [_delegate parserDidStartDictionary:self]; 224 | } 225 | 226 | - (void)_endDictionary { 227 | [_delegate parserDidEndDictionary:self]; 228 | } 229 | 230 | - (void)_startArray { 231 | [_delegate parserDidStartArray:self]; 232 | } 233 | 234 | - (void)_endArray { 235 | [_delegate parserDidEndArray:self]; 236 | } 237 | 238 | //! @endinternal 239 | 240 | - (unsigned int)bytesConsumed { 241 | return _handle ? (unsigned int)yajl_get_bytes_consumed(_handle) : 0; 242 | } 243 | 244 | - (YAJLParserStatus)parse:(NSData *)data { 245 | if (!_handle) { 246 | _handle = yajl_alloc(&callbacks, NULL, (__bridge void *)(self)); 247 | yajl_config(_handle, yajl_allow_comments, (_parserOptions & YAJLParserOptionsAllowComments) ? 1 : 0); 248 | yajl_config(_handle, yajl_dont_validate_strings, (_parserOptions & YAJLParserOptionsCheckUTF8) ? 1 : 0); 249 | 250 | if (!_handle) { 251 | self.parserError = [self _errorForStatus:YAJLParserErrorCodeAllocError message:@"Unable to allocate YAJL handle" value:nil]; 252 | return YAJLParserStatusError; 253 | } 254 | } 255 | 256 | yajl_status status = yajl_parse(_handle, data.bytes, (unsigned int) data.length); 257 | if (status == yajl_status_client_canceled) { 258 | // We cancelled because we encountered an error here in the client; 259 | // and parserError should be already set 260 | NSAssert(self.parserError, @"Client cancelled, but we have no parserError set"); 261 | return YAJLParserStatusError; 262 | } else if (status == yajl_status_error) { 263 | unsigned char *errorMessage = yajl_get_error(_handle, 1, data.bytes, (unsigned int) data.length); 264 | NSString *errorString = @((char *)errorMessage); 265 | self.parserError = [self _errorForStatus:status message:errorString value:nil]; 266 | yajl_free_error(_handle, errorMessage); 267 | return YAJLParserStatusError; 268 | } else if (status == yajl_status_ok) { 269 | return YAJLParserStatusOK; 270 | } else { 271 | self.parserError = [self _errorForStatus:status message:[NSString stringWithFormat:@"Unexpected status %d", status] value:nil]; 272 | return YAJLParserStatusError; 273 | } 274 | } 275 | 276 | @end 277 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gabriel Handford on 3/1/09. 3 | // Copyright 2009. All rights reserved. 4 | // 5 | // Permission is hereby granted, free of charge, to any person 6 | // obtaining a copy of this software and associated documentation 7 | // files (the "Software"), to deal in the Software without 8 | // restriction, including without limitation the rights to use, 9 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the 11 | // Software is furnished to do so, subject to the following 12 | // conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be 15 | // included in all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | // OTHER DEALINGS IN THE SOFTWARE. 25 | // -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.5 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "YAJLO", 8 | products: [ 9 | .library(name: "YAJLO", targets: ["YAJLO"]), 10 | ], 11 | dependencies: [ 12 | ], 13 | targets: [ 14 | .target( 15 | name: "YAJLO", 16 | dependencies: [], 17 | path: "./", 18 | exclude: ["YAJLO.podspec", "CHANGELOG.md", "README.md", "Tests", "LICENSE", "Tests-Info.plist", "Info.plist"], 19 | sources: ["./Classes", "./yajl-2.1.0"], 20 | publicHeadersPath: "./Classes", 21 | cxxSettings: [ 22 | .headerSearchPath("./yajl-2.1.0"), 23 | .headerSearchPath("./yajl-2.1.0/api") 24 | ] 25 | ), 26 | .testTarget( 27 | name: "yajlTests", 28 | dependencies: ["YAJLO"] 29 | ), 30 | ] 31 | ) 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YAJL Framework 2 | 3 | The YAJL framework is an Objective-C framework for the [YAJL](http://lloyd.github.com/yajl/) SAX-style JSON parser. 4 | 5 | ## Features 6 | 7 | - Stream parsing, comments in JSON, better error messages. 8 | - Parse directly from NSString or NSData. 9 | - Generate JSON from default or custom types. 10 | - Properly handles large numeric types. 11 | - Document style parser. 12 | - Error by exception or out error. 13 | 14 | # Integration 15 | 16 | ## CocoaPods 17 | 18 | ```ruby 19 | pod "YAJLO" 20 | ``` 21 | 22 | ## Swift Package Manager 23 | 24 | You can use The Swift Package Manager to install yajl-objc by adding the proper description to your Package.swift file: 25 | 26 | ```swift 27 | // swift-tools-version:5.5 28 | import PackageDescription 29 | 30 | let package = Package( 31 | name: "YOUR_PROJECT_NAME", 32 | dependencies: [ 33 | .package(url: "https://github.com/gabriel/yajl-objc.git", from: "0.3.4"), 34 | ] 35 | ) 36 | ``` 37 | 38 | # Usage 39 | 40 | ```objc 41 | #import 42 | #import 43 | #import 44 | #import 45 | ``` 46 | 47 | ### To parse JSON from NSData 48 | 49 | ```objc 50 | NSData *JSONData = [NSData dataWithContentsOfFile:@"example.json"]; 51 | NSArray *arrayFromData = [JSONData yajl_JSON]; 52 | ``` 53 | 54 | ### To parse JSON from NSString 55 | 56 | ```objc 57 | NSString *JSONString = @"[1, 2, 3]"; 58 | NSArray *arrayFromString = [JSONString yajl_JSON]; 59 | ``` 60 | 61 | ### To parse JSON from NSString with error and comments 62 | 63 | ```objc 64 | // With options and out error 65 | NSString *JSONString = @"[1, 2, 3] // Allow comments"; 66 | NSError *error = nil; 67 | NSArray *arrayFromString = [JSONString yajl_JSONWithOptions:YAJLParserOptionsAllowComments error:&error]; 68 | ``` 69 | 70 | ### To generate JSON from an object, NSArray, NSDictionary, etc. 71 | 72 | ```objc 73 | NSDictionary *dict = [NSDictionary dictionaryWithObject:@"value" forKey:@"key"]; 74 | NSString *JSONString = [dict yajl_JSONString]; 75 | // ==> {"key":"value"} 76 | ``` 77 | 78 | ### To generate JSON from an object, beautified with custom indent 79 | 80 | ```objc 81 | // Beautified with custon indent string 82 | NSArray *array = [NSArray arrayWithObjects:@"value1", @"value2", nil]; 83 | NSString *JSONString = [dict yajl_JSONStringWithOptions:YAJLGenOptionsBeautify indentString:@" "]; 84 | ``` 85 | 86 | ### To use the streaming (or SAX style) parser, use YAJLParser 87 | 88 | ```objc 89 | NSData *data = [NSData dataWithContentsOfFile:@"example.json"]; 90 | 91 | YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:YAJLParserOptionsAllowComments]; 92 | parser.delegate = self; 93 | [parser parse:data]; 94 | if (parser.parserError) { 95 | NSLog(@"Error:\n%@", parser.parserError); 96 | } 97 | parser.delegate = nil; 98 | 99 | // Include delegate methods from YAJLParserDelegate 100 | - (void)parserDidStartDictionary:(YAJLParser *)parser { } 101 | - (void)parserDidEndDictionary:(YAJLParser *)parser { } 102 | 103 | - (void)parserDidStartArray:(YAJLParser *)parser { } 104 | - (void)parserDidEndArray:(YAJLParser *)parser { } 105 | 106 | - (void)parser:(YAJLParser *)parser didMapKey:(NSString *)key { } 107 | - (void)parser:(YAJLParser *)parser didAdd:(id)value { } 108 | ``` 109 | 110 | ### Parser Options 111 | 112 | There are options when parsing that can be specified with initWithParserOptions: (YAJLParser). 113 | 114 | - `YAJLParserOptionsAllowComments`: Allows comments in JSON 115 | - `YAJLParserOptionsCheckUTF8`: Will verify UTF-8 116 | - `YAJLParserOptionsStrictPrecision`: Will force strict precision and return integer overflow error, if number is greater than long long. 117 | 118 | ### Parsing as data becomes available 119 | 120 | ```objc 121 | YAJLParser *parser = [[YAJLParser alloc] init]; 122 | parser.delegate = self; 123 | 124 | // A chunk of data comes... 125 | YAJLParserStatus status = [parser parse:chunk1]; 126 | // 'status' should be YAJLParserStatusInsufficientData, if its not finished 127 | if (parser.parserError) 128 | NSLog(@"Error:\n%@", parser.parserError); 129 | 130 | // Another chunk of data comes... 131 | YAJLParserStatus status = [parser parse:chunk2]; 132 | // 'status' should be YAJLParserStatusOK if its finished 133 | if (parser.parserError) 134 | NSLog(@"Error:\n%@", parser.parserError); 135 | ``` 136 | 137 | ### Document style parsing 138 | 139 | To use the document style, use YAJLDocument. Usage should be very similar to NSXMLDocument. 140 | 141 | ```objc 142 | NSData *data = [NSData dataWithContentsOfFile:@"example.json"]; 143 | NSError *error = nil; 144 | YAJLDocument *document = [[YAJLDocument alloc] initWithData:data parserOptions:YAJLParserOptionsNone error:&error]; 145 | // Access root element at document.root 146 | NSLog(@"Root: %@", document.root); 147 | ``` 148 | 149 | ### Document style parsing as data becomes available 150 | 151 | ```objc 152 | YAJLDocument *document = [[YAJLDocument alloc] init]; 153 | document.delegate = self; 154 | 155 | NSError *error = nil; 156 | [document parse:chunk1 error:error]; 157 | [document parse:chunk2 error:error]; 158 | 159 | // You can access root element at document.root 160 | NSLog(@"Root: %@", document.root); 161 | 162 | // Or via the YAJLDocumentDelegate delegate methods 163 | 164 | - (void)document:(YAJLDocument *)document didAddDictionary:(NSDictionary *)dict { } 165 | - (void)document:(YAJLDocument *)document didAddArray:(NSArray *)array { } 166 | - (void)document:(YAJLDocument *)document didAddObject:(id)object toArray:(NSArray *)array { } 167 | - (void)document:(YAJLDocument *)document didSetObject:(id)object forKey:(id)key inDictionary:(NSDictionary *)dict { } 168 | ``` 169 | 170 | ### Load JSON from Bundle 171 | 172 | ```objc 173 | id JSONValue = [[NSBundle mainBundle] yajl_JSONFromResource:@"kegs.json"]; 174 | ``` 175 | 176 | ### Customized Encoding 177 | 178 | To implement JSON encodable value for custom objects or override for existing objects, implement - (id)JSON; 179 | 180 | For example: 181 | 182 | ```objc 183 | @interface CustomObject : NSObject 184 | @end 185 | 186 | @implementation CustomObject 187 | 188 | - (id)JSON { 189 | return [NSArray arrayWithObject:[NSNumber numberWithInteger:1]]; 190 | } 191 | 192 | @end 193 | ``` 194 | -------------------------------------------------------------------------------- /Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/GHUnitTestMain.m: -------------------------------------------------------------------------------- 1 | // 2 | // GHUnitTestMain.m 3 | // GHUnit 4 | // 5 | // Created by Gabriel Handford on 2/22/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | #import 33 | #import 34 | 35 | int main(int argc, char *argv[]) { 36 | @autoreleasepool { 37 | 38 | // Register any special test case classes 39 | //[[GHTesting sharedInstance] registerClassName:@"GHSpecialTestCase"]; 40 | 41 | int retVal = 0; 42 | // If GHUNIT_CLI is set we are using the command line interface and run the tests 43 | // Otherwise load the GUI app 44 | if (getenv("GHUNIT_CLI")) { 45 | retVal = [GHTestRunner run]; 46 | } else { 47 | // To run all tests (from ENV) 48 | [[GHTestApp alloc] init]; 49 | // To run a different test suite: 50 | //GHTestSuite *suite = [GHTestSuite suiteWithTestFilter:@"GHSlowTest,GHAsyncTestCaseTest"]; 51 | //GHTestApp *app = [[GHTestApp alloc] initWithSuite:suite]; 52 | // Or set global: 53 | //GHUnitTest = @"GHSlowTest"; 54 | [NSApp run]; 55 | } 56 | return retVal; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Tests/NSDataTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDataTest.m 3 | // YAJLIPhone 4 | // 5 | // Created by Gabriel Handford on 10/7/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | 9 | #import "YAJLTestCase.h" 10 | #import "NSObject+YAJL.h" 11 | 12 | @interface NSDataTest : YAJLTestCase 13 | @end 14 | 15 | @implementation NSDataTest 16 | 17 | - (void)testExample { 18 | NSData *data = [[self loadString:@"example"] dataUsingEncoding:NSUTF8StringEncoding]; 19 | id JSON = [data yajl_JSON]; 20 | 21 | XCTAssertTrue([JSON isKindOfClass:[NSDictionary class]]); 22 | NSDictionary *glossary = JSON[@"glossary"]; 23 | XCTAssertNotNil(glossary); 24 | NSString *title = glossary[@"title"]; 25 | XCTAssertEqualObjects(title, @"example glossary"); 26 | } 27 | 28 | @end -------------------------------------------------------------------------------- /Tests/NSObjectTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObjectTest.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 7/23/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | 9 | #import "YAJLTestCase.h" 10 | #import "NSObject+YAJL.h" 11 | 12 | @interface NSObjectTest : YAJLTestCase 13 | @end 14 | 15 | @interface CustomJSONObject : NSObject 16 | @end 17 | 18 | @implementation NSObjectTest 19 | 20 | - (void)testDictionary { 21 | NSDictionary *dict = @{@"key2": @[@"arrayValue1", @YES, @NO, [NSNull null], 22 | @1, @234234.234234, [NSDecimalNumber notANumber]]}; 23 | 24 | NSString *JSONString = [dict yajl_JSONStringWithOptions:YAJLGenOptionsBeautify indentString:@" "]; 25 | 26 | NSString *expected = [self loadString:@"gen_expected1"]; 27 | XCTAssertEqualObjects(JSONString, expected); 28 | } 29 | 30 | - (void)testArray { 31 | NSArray *array = @[@"arrayValue1", @YES, @NO, [NSNull null], 32 | @1, @234234.234234]; 33 | 34 | NSString *JSONString = [array yajl_JSONStringWithOptions:YAJLGenOptionsBeautify indentString:@" "]; 35 | 36 | NSString *expected = [self loadString:@"object_expected_array"]; 37 | XCTAssertEqualObjects(JSONString, expected); 38 | } 39 | 40 | - (void)testCustom { 41 | CustomJSONObject *obj = [[CustomJSONObject alloc] init]; 42 | NSString *JSONString = [obj yajl_JSONString]; 43 | NSString *expected = @"[\"Test\"]"; 44 | XCTAssertEqualObjects(JSONString, expected); 45 | } 46 | 47 | - (void)testComments { 48 | NSError *error = nil; 49 | id JSONValue = [[self loadData:@"comments"] yajl_JSONWithOptions:YAJLParserOptionsAllowComments error:&error]; 50 | NSLog(@"Error=%@", error); 51 | XCTAssertNil(error); 52 | XCTAssertNotNil(JSONValue); 53 | } 54 | 55 | - (void)testOverflow { 56 | NSDictionary *dict = [[self loadData:@"overflow2"] yajl_JSON]; 57 | XCTAssertNotNil(dict); 58 | XCTAssertTrue([dict count] > 0); 59 | } 60 | 61 | - (void)testPrecision { 62 | NSError *error = nil; 63 | id JSONValue = [[self loadData:@"overflow2"] yajl_JSONWithOptions:YAJLParserOptionsStrictPrecision error:&error]; 64 | NSLog(@"Error=%@", error); 65 | XCTAssertNotNil(error); 66 | NSLog(@"JSONValue=%@", JSONValue); 67 | XCTAssertNotNil(JSONValue); 68 | XCTAssertTrue([JSONValue count] == 0); 69 | } 70 | 71 | @end 72 | 73 | 74 | @implementation CustomJSONObject 75 | 76 | - (id)JSON { 77 | return @[@"Test"]; 78 | } 79 | 80 | @end -------------------------------------------------------------------------------- /Tests/NSStringTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSStringTest.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 7/23/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | 9 | #import "YAJLTestCase.h" 10 | 11 | #import "NSObject+YAJL.h" 12 | 13 | @interface NSStringTest : YAJLTestCase 14 | @end 15 | 16 | @implementation NSStringTest 17 | 18 | - (void)testExample { 19 | NSString *exampleString = [self loadString:@"example"]; 20 | NSLog(@"Example string: %@", exampleString); 21 | id JSON = [exampleString yajl_JSON]; 22 | 23 | XCTAssertTrue([JSON isKindOfClass:[NSDictionary class]]); 24 | NSDictionary *glossary = JSON[@"glossary"]; 25 | XCTAssertNotNil(glossary); 26 | NSString *title = glossary[@"title"]; 27 | XCTAssertEqualObjects(title, @"example glossary"); 28 | } 29 | 30 | - (void)testArrayNumbers { 31 | NSString *JSONString = @"[1, 2, 3]"; 32 | NSArray *JSON = [JSONString yajl_JSON]; 33 | NSArray *expected = @[@1, @2, @3]; 34 | XCTAssertEqualObjects(expected, JSON); 35 | } 36 | 37 | - (void)testAllowComments { 38 | NSString *JSONString = @"[1, 2, 3] // Allow comments"; 39 | NSError *error = nil; 40 | NSArray *JSON = [JSONString yajl_JSONWithOptions:YAJLParserOptionsAllowComments error:&error]; 41 | NSArray *expected = @[@1, @2, @3]; 42 | XCTAssertEqualObjects(expected, JSON); 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Tests/RunTests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # If we aren't running from the command line, then exit 4 | if [ "$GHUNIT_CLI" != "1" ]; then 5 | exit 0 6 | fi 7 | 8 | export DYLD_ROOT_PATH="$SDKROOT" 9 | export DYLD_FRAMEWORK_PATH="$CONFIGURATION_BUILD_DIR" 10 | export IPHONE_SIMULATOR_ROOT="$SDKROOT" 11 | 12 | export MallocScribble=YES 13 | export MallocPreScribble=YES 14 | export MallocGuardEdges=YES 15 | export MallocStackLogging=YES 16 | export MallocStackLoggingNoCompact=YES 17 | export NSAutoreleaseFreedObjectCheckEnabled=YES 18 | 19 | export CFZombieLevel=3 20 | export NSZombieEnabled=YES 21 | 22 | "$TARGET_BUILD_DIR/$EXECUTABLE_PATH" -RegisterForSystemEvents 23 | RETVAL=$? 24 | 25 | exit $RETVAL 26 | 27 | 28 | -------------------------------------------------------------------------------- /Tests/Samples/comments.json: -------------------------------------------------------------------------------- 1 | { 2 | "Test with comments (1)": 1, // Comment 3 | "Test with comments (2)": 2 /* Comment */ 4 | } -------------------------------------------------------------------------------- /Tests/Samples/document_streaming.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": { 3 | "array1": [ 1 ], 4 | "array2": [ 2 ], 5 | "array3": [ 3 ], 6 | "array4": [ 4 ], 7 | "array5": [ 5 ], 8 | "array6": [ 6 ] 9 | } 10 | } -------------------------------------------------------------------------------- /Tests/Samples/error.json: -------------------------------------------------------------------------------- 1 | { 'bad json -------------------------------------------------------------------------------- /Tests/Samples/error2.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": { 3 | "bar": 2, 4 | } 5 | } -------------------------------------------------------------------------------- /Tests/Samples/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "glossary": { 3 | "title": "example glossary", 4 | "GlossDiv": { 5 | "title": "S", 6 | "GlossList": { 7 | "GlossEntry": { 8 | "ID": "SGML", 9 | "SortAs": "SGML", 10 | "GlossTerm": "Standard Generalized Markup Language", 11 | "Acronym": "SGML", 12 | "Abbrev": "ISO 8879:1986", 13 | "GlossDef": { 14 | "para": "A meta-markup language, used to create markup languages such as DocBook.", 15 | "GlossSeeAlso": ["GML", "XML"] 16 | }, 17 | "GlossSee": "markup" 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/Samples/gen_expected1.json: -------------------------------------------------------------------------------- 1 | { 2 | "key2": [ 3 | "arrayValue1", 4 | true, 5 | false, 6 | null, 7 | 1, 8 | 234234.234234, 9 | null 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /Tests/Samples/gen_expected2.json: -------------------------------------------------------------------------------- 1 | {"key2":["arrayValue1",true,false,null,1,234234.234234,null]} -------------------------------------------------------------------------------- /Tests/Samples/gen_expected_ignore_unknown1.json: -------------------------------------------------------------------------------- 1 | {"date":null} -------------------------------------------------------------------------------- /Tests/Samples/gen_expected_plist1.json: -------------------------------------------------------------------------------- 1 | [1000,"QUJDREVG","http://www.yelp.com/"] -------------------------------------------------------------------------------- /Tests/Samples/object_expected_array.json: -------------------------------------------------------------------------------- 1 | [ 2 | "arrayValue1", 3 | true, 4 | false, 5 | null, 6 | 1, 7 | 234234.234234 8 | ] 9 | -------------------------------------------------------------------------------- /Tests/Samples/overflow.json: -------------------------------------------------------------------------------- 1 | { 2 | "max_double": 1.79769e+308, 3 | "overflow": 1.79769e+309 4 | } -------------------------------------------------------------------------------- /Tests/Samples/overflow2.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1": 12343434343434343434343434344343434, 3 | "key2": 343434343434344343434343434 4 | } -------------------------------------------------------------------------------- /Tests/Samples/overflow_longlong.json: -------------------------------------------------------------------------------- 1 | { 2 | "max_longlong": 9223372036854775807, 3 | "min_longlong": -9223372036854775808, 4 | "overflow": 9223372036854775808 5 | } -------------------------------------------------------------------------------- /Tests/Samples/overflow_longlong_macosx.json: -------------------------------------------------------------------------------- 1 | { 2 | "max_longlong": 9223372036854775807, 3 | "min_longlong": -9223372036854775807, 4 | "overflow": 9223372036854775807 5 | } -------------------------------------------------------------------------------- /Tests/Samples/stream1.json: -------------------------------------------------------------------------------- 1 | { 2 | "glossary": { 3 | "title": "example glossary", 4 | "GlossDiv": { 5 | "title": "S", 6 | "GlossList": { 7 | "GlossEntry": { -------------------------------------------------------------------------------- /Tests/Samples/stream2.json: -------------------------------------------------------------------------------- 1 | "ID": "SGML", 2 | "SortAs": "SGML", 3 | "GlossTerm": "Standard Generalized Markup Language", 4 | "Acronym": "SGML", 5 | "Abbrev": "ISO 8879:1986", 6 | "GlossDef": { 7 | "para": "A meta-markup language, used to create markup languages such as DocBook.", 8 | "GlossSeeAlso": ["GML", "XML"] 9 | }, 10 | "GlossSee": "markup" 11 | } 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/Samples/stream_array1.json: -------------------------------------------------------------------------------- 1 | [1, 2, 3 -------------------------------------------------------------------------------- /Tests/Samples/stream_array2.json: -------------------------------------------------------------------------------- 1 | , 4, 5, 6] -------------------------------------------------------------------------------- /Tests/Samples/twitter.json: -------------------------------------------------------------------------------- 1 | { 2 | "geo": { 3 | "type": "Point", 4 | "coordinates": [ 5 | 50.96165050, 6 | -1.42539830 7 | ] 8 | }, 9 | "source": "Tweetie", 10 | "truncated": false, 11 | "favorited": false, 12 | "user": { 13 | "profile_background_image_url": "http://s.twimg.com/a/1261078355/images/themes/theme1/bg.png", 14 | "description": "", 15 | "profile_link_color": "0000ff", 16 | "profile_background_tile": false, 17 | "statuses_count": 5, 18 | "profile_background_color": "9ae4e8", 19 | "following": true, 20 | "followers_count": 1, 21 | "profile_sidebar_fill_color": "e0ff92", 22 | "friends_count": 1, 23 | "time_zone": "London", 24 | "profile_sidebar_border_color": "87bc44", 25 | "protected": false, 26 | "url": "http://meltinglobster.com", 27 | "notifications": false, 28 | "favourites_count": 0, 29 | "profile_image_url": "http://s.twimg.com/a/1261078355/images/default_profile_5_normal.png", 30 | "location": "", 31 | "name": "MeltingLobster", 32 | "id": 92150511, 33 | "verified": false, 34 | "geo_enabled": true, 35 | "utc_offset": 0, 36 | "created_at": "Mon Nov 23 23:59:37 +0000 2009", 37 | "profile_text_color": "000000", 38 | "screen_name": "meltinglobster" 39 | }, 40 | "in_reply_to_user_id": null, 41 | "in_reply_to_status_id": null, 42 | "in_reply_to_screen_name": null, 43 | "id": 6926861840, 44 | "text": "Geotweet again", 45 | "created_at": "Tue Dec 22 11:56:36 +0000 2009" 46 | } -------------------------------------------------------------------------------- /Tests/Samples/twitter_snowflake.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "coordinates": null, 4 | "truncated": false, 5 | "created_at": "Thu Oct 14 22:20:15 +0000 2010", 6 | "favorited": false, 7 | "entities": { 8 | "urls": [ 9 | ], 10 | "hashtags": [ 11 | ], 12 | "user_mentions": [ 13 | { 14 | "name": "Matt Harris", 15 | "id": 777925, 16 | "id_str": "777925", 17 | "indices": [ 18 | 0, 19 | 14 20 | ], 21 | "screen_name": "themattharris" 22 | } 23 | ] 24 | }, 25 | "text": "@themattharris hey how are things?", 26 | "annotations": null, 27 | "contributors": [ 28 | { 29 | "id": 819797, 30 | "id_str": "819797", 31 | "screen_name": "episod" 32 | } 33 | ], 34 | "id": 12738165059, 35 | "id_str": "12738165059", 36 | "retweet_count": 0, 37 | "geo": null, 38 | "retweeted": false, 39 | "in_reply_to_user_id": 777925, 40 | "in_reply_to_user_id_str": "777925", 41 | "in_reply_to_screen_name": "themattharris", 42 | "user": { 43 | "id": 6253282, 44 | "id_str": "6253282" 45 | }, 46 | "source": "web", 47 | "place": null, 48 | "in_reply_to_status_id": 12738040524, 49 | "in_reply_to_status_id_str": "12738040524" 50 | } 51 | ] -------------------------------------------------------------------------------- /Tests/TwitterTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // TwitterTest.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 12/22/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | 9 | #import "YAJLTestCase.h" 10 | 11 | #import "NSObject+YAJL.h" 12 | 13 | @interface TwitterTest : YAJLTestCase 14 | @end 15 | 16 | @implementation TwitterTest 17 | 18 | - (void)testCoordinates { 19 | NSString *twitterJSONString = [self loadString:@"twitter"]; 20 | id JSON = [twitterJSONString yajl_JSON]; 21 | 22 | XCTAssertTrue([JSON isKindOfClass:[NSDictionary class]]); 23 | NSDictionary *geo = JSON[@"geo"]; 24 | XCTAssertNotNil(geo); 25 | NSArray *coordinates = geo[@"coordinates"]; 26 | NSNumber *coord1 = coordinates[0]; 27 | NSNumber *coord2 = coordinates[1]; 28 | 29 | XCTAssertEqualObjects(@50.96165050, coord1); 30 | XCTAssertEqualObjects(@-1.42539830, coord2); 31 | } 32 | 33 | - (void)testSnowflake { 34 | // From Twitter snowflake discussion: http://groups.google.com/group/twitter-development-talk/browse_thread/thread/6a16efa375532182# 35 | NSString *twitterJSONString = [self loadString:@"twitter_snowflake"]; 36 | id JSON = [twitterJSONString yajl_JSON]; 37 | 38 | XCTAssertTrue([JSON isKindOfClass:[NSArray class]]); 39 | NSDictionary *tweet = JSON[0]; 40 | XCTAssertNotNil(tweet); 41 | NSNumber *identifier = tweet[@"id"]; 42 | XCTAssertEqualObjects([NSNumber numberWithLongLong:12738165059], identifier); 43 | NSString *identifierStr = tweet[@"id_str"]; 44 | XCTAssertEqualObjects(@"12738165059", identifierStr); 45 | XCTAssertEqualObjects([identifier stringValue], identifierStr); 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Tests/YAJLDocumentDelegateTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLDocumentDelegateTest.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 3/29/10. 6 | // Copyright 2010 Yelp. All rights reserved. 7 | // 8 | 9 | #import "YAJLTestCase.h" 10 | #import "YAJLDocument.h" 11 | 12 | @interface YAJLDocumentDelegateTest : YAJLTestCase {} 13 | @end 14 | 15 | @implementation YAJLDocumentDelegateTest 16 | 17 | - (void)test { 18 | NSData *data = [self loadData:@"document_streaming"]; 19 | NSError *error = nil; 20 | YAJLDocument *document = [[YAJLDocument alloc] init]; 21 | document.delegate = self; 22 | [document parse:data error:&error]; 23 | XCTAssertNil(error); 24 | } 25 | 26 | - (void)document:(YAJLDocument *)document didSetObject:(id)object forKey:(id)key inDictionary:(NSDictionary *)dict { 27 | if ([key isEqualToString:@"test"]) return; 28 | 29 | static NSInteger index = 1; 30 | NSString *expectedKey = [NSString stringWithFormat:@"array%ld", (signed long)index]; 31 | NSArray *expectedValue = @[@(index)]; 32 | index++; 33 | XCTAssertEqualObjects(expectedKey, key); 34 | XCTAssertEqualObjects(expectedValue, object); 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Tests/YAJLDocumentTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLDocumentTest.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 3/1/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | 9 | #import "YAJLTestCase.h" 10 | #import "YAJLDocument.h" 11 | 12 | @interface YAJLDocumentTest : YAJLTestCase {} 13 | @end 14 | 15 | @implementation YAJLDocumentTest 16 | 17 | - (YAJLDocument *)_loadDocument:(NSString *)sampleName parserOptions:(YAJLParserOptions)parserOptions error:(NSError **)error { 18 | NSData *data = [self loadData:sampleName]; 19 | YAJLDocument *document = [[YAJLDocument alloc] initWithData:data parserOptions:parserOptions error:error]; 20 | return document; 21 | } 22 | 23 | - (void)test { 24 | NSError *error = nil; 25 | YAJLDocument *document = [self _loadDocument:@"example" parserOptions:0 error:&error]; 26 | if (error) XCTFail(@"Error: %@", error); 27 | NSLog(@"Root: %@", document.root); 28 | } 29 | 30 | - (void)testStreaming { 31 | YAJLDocument *document = [[YAJLDocument alloc] init]; 32 | 33 | NSError *error = nil; 34 | NSData *data1 = [self loadData:@"stream_array1"]; 35 | YAJLParserStatus status1 = [document parse:data1 error:&error]; 36 | XCTAssertEqual(status1, YAJLParserStatusOK); 37 | if (error) XCTFail(@"Error: %@", error); 38 | NSLog(@"First part: %@", document.root); 39 | 40 | NSData *data2 = [self loadData:@"stream_array2"]; 41 | YAJLParserStatus status2 = [document parse:data2 error:&error]; 42 | XCTAssertEqual(status2, YAJLParserStatusOK); 43 | if (error) XCTFail(@"Error: %@", error); 44 | 45 | NSLog(@"Root: %@", document.root); 46 | } 47 | 48 | - (void)testDoubleOverflow { 49 | NSError *error = nil; 50 | YAJLDocument *document = [self _loadDocument:@"overflow" parserOptions:0 error:&error]; 51 | XCTAssertNotNil(document); 52 | NSLog(@"Root: %@", document.root); 53 | YAJLParserStatus status = document.parserStatus; 54 | XCTAssertEqual(status, (NSUInteger)YAJLParserStatusError, @"Should have error status"); 55 | 56 | if (error) { 57 | NSLog(@"Parse error:\n%@", error); 58 | XCTAssertEqual([error code], (NSInteger)YAJLParserErrorCodeDoubleOverflow); 59 | XCTAssertEqualObjects([error userInfo][YAJLParserValueKey], @"1.79769e+309"); 60 | } else { 61 | XCTFail(@"Should have error"); 62 | } 63 | } 64 | 65 | - (void)testOverflow2 { 66 | NSError *error = nil; 67 | YAJLDocument *document = [self _loadDocument:@"overflow2" parserOptions:0 error:&error]; 68 | NSLog(@"Root: %@", document.root); 69 | YAJLParserStatus status = document.parserStatus; 70 | XCTAssertEqual(status, (NSUInteger)YAJLParserStatusOK, @"Should have OK status"); 71 | XCTAssertEqualObjects((document.root)[@"key1"], @12343434343434343434343434344343434.0); 72 | XCTAssertEqualObjects((document.root)[@"key2"], @343434343434344343434343434.0); 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /Tests/YAJLGenTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLGenTest.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 7/19/09. 6 | // Copyright 2009 . All rights reserved. 7 | // 8 | 9 | #import "YAJLTestCase.h" 10 | 11 | #import "YAJLGen.h" 12 | 13 | @interface YAJLGenTest : YAJLTestCase {} 14 | @end 15 | 16 | @implementation YAJLGenTest 17 | 18 | - (void)testGen1 { 19 | YAJLGen *gen = [[YAJLGen alloc] initWithGenOptions:YAJLGenOptionsBeautify indentString:@" "]; 20 | [gen startDictionary]; 21 | [gen string:@"key2"]; 22 | [gen startArray]; 23 | [gen string:@"arrayValue1"]; 24 | [gen bool:YES]; 25 | [gen bool:NO]; 26 | [gen null]; 27 | [gen number:@1]; 28 | [gen number:@234234.234234]; 29 | [gen number:[NSDecimalNumber notANumber]]; 30 | [gen endArray]; 31 | [gen endDictionary]; 32 | NSString *buffer = [gen buffer]; 33 | 34 | NSString *expected = [self loadString:@"gen_expected1"]; 35 | 36 | XCTAssertEqualObjects(buffer, expected); 37 | } 38 | 39 | - (void)testGen2 { 40 | YAJLGen *gen = [[YAJLGen alloc] init]; 41 | [gen startDictionary]; 42 | [gen string:@"key2"]; 43 | [gen startArray]; 44 | [gen string:@"arrayValue1"]; 45 | [gen bool:YES]; 46 | [gen bool:NO]; 47 | [gen null]; 48 | [gen number:@1]; 49 | [gen number:@234234.234234]; 50 | [gen number:[NSDecimalNumber notANumber]]; 51 | [gen endArray]; 52 | [gen endDictionary]; 53 | NSString *buffer = [gen buffer]; 54 | [gen clear]; 55 | 56 | NSString *expected = [self loadString:@"gen_expected2"]; 57 | XCTAssertEqualObjects(buffer, expected); 58 | } 59 | 60 | - (void)testGenObject1 { 61 | NSDictionary *dict = @{@"key2": @[@"arrayValue1", @YES, @NO, [NSNull null], 62 | @1, @234234.234234, [NSDecimalNumber notANumber]]}; 63 | 64 | YAJLGen *gen = [[YAJLGen alloc] initWithGenOptions:YAJLGenOptionsBeautify indentString:@" "]; 65 | [gen object:dict]; 66 | NSString *buffer = [gen buffer]; 67 | 68 | NSString *expected = [self loadString:@"gen_expected1"]; 69 | XCTAssertEqualObjects(buffer, expected); 70 | } 71 | 72 | - (void)testGenObjectUnknownType { 73 | NSDictionary *dict = @{@"date": [NSDate dateWithTimeIntervalSince1970:1]}; 74 | YAJLGen *gen = [[YAJLGen alloc] init]; 75 | XCTAssertThrows([gen object:dict]); 76 | } 77 | 78 | - (void)testGenObjectIgnoreUnknownType { 79 | NSDictionary *dict = @{@"date": [NSDate dateWithTimeIntervalSince1970:1]}; 80 | 81 | YAJLGen *gen = [[YAJLGen alloc] initWithGenOptions:YAJLGenOptionsIgnoreUnknownTypes indentString:@""]; 82 | [gen object:dict]; 83 | NSString *buffer = [gen buffer]; 84 | 85 | NSString *expected = [self loadString:@"gen_expected_ignore_unknown1"]; 86 | XCTAssertEqualObjects(buffer, expected); 87 | } 88 | 89 | - (void)testGenObjectPListTypes { 90 | const char *testData = "ABCDEFG"; 91 | NSArray *array = @[[NSDate dateWithTimeIntervalSince1970:1], 92 | [NSData dataWithBytes:testData length:6], 93 | [NSURL URLWithString:@"http://www.yelp.com/"]]; 94 | 95 | YAJLGen *gen = [[YAJLGen alloc] initWithGenOptions:YAJLGenOptionsIncludeUnsupportedTypes indentString:@""]; 96 | [gen object:array]; 97 | NSString *buffer = [gen buffer]; 98 | 99 | NSString *expected = [self loadString:@"gen_expected_plist1"]; 100 | XCTAssertEqualObjects(buffer, expected); 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /Tests/YAJLParserTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLParserTest.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 6/14/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | 9 | #import "YAJLTestCase.h" 10 | #import "YAJLParser.h" 11 | 12 | @interface YAJLParserTest : YAJLTestCase {} 13 | @end 14 | 15 | @implementation YAJLParserTest 16 | 17 | - (void)test { 18 | YAJLParser *parser = [[YAJLParser alloc] init]; 19 | [parser parse:[self loadData:@"example"]]; 20 | 21 | NSError *error = parser.parserError; 22 | if (error) { 23 | NSLog(@"Parse error:\n%@", error); 24 | XCTFail(@"Error: %@", error); 25 | } 26 | } 27 | 28 | - (void)testError { 29 | YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:0]; 30 | YAJLParserStatus status = [parser parse:[self loadData:@"error"]]; 31 | XCTAssertTrue(status == YAJLParserStatusError, @"Should have error status"); 32 | 33 | NSError *error = parser.parserError; 34 | if (error) { 35 | NSLog(@"Parse error:\n%@", error); 36 | } else { 37 | XCTFail(@"Should have error"); 38 | } 39 | } 40 | 41 | - (void)testError2 { 42 | YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:0]; 43 | YAJLParserStatus status = [parser parse:[self loadData:@"error2"]]; 44 | XCTAssertTrue(status == YAJLParserStatusError, @"Should have error status"); 45 | 46 | NSError *error = parser.parserError; 47 | if (error) { 48 | NSLog(@"Parse error:\n%@", error); 49 | XCTAssertTrue([[error localizedDescription] hasPrefix:@"parse error: invalid object key (must be a string)\n"]); 50 | } else { 51 | XCTFail(@"Should have error"); 52 | } 53 | } 54 | 55 | - (void)testComments { 56 | YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:YAJLParserOptionsAllowComments]; 57 | YAJLParserStatus status = [parser parse:[self loadData:@"comments"]]; 58 | XCTAssertTrue(status == YAJLParserStatusOK, @"Should have OK status"); 59 | 60 | NSError *error = parser.parserError; 61 | if (error) { 62 | NSLog(@"Parse error:\n%@", error); 63 | XCTFail(@"Error: %@", error); 64 | } 65 | } 66 | 67 | - (void)testFailOnComments { 68 | YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:0]; 69 | YAJLParserStatus status = [parser parse:[self loadData:@"comments"]]; 70 | XCTAssertTrue(status == YAJLParserStatusError, @"Should have error status"); 71 | 72 | NSError *error = parser.parserError; 73 | if (error) { 74 | NSLog(@"Parse error:\n%@", error); 75 | } else { 76 | XCTFail(@"Should have error"); 77 | } 78 | } 79 | 80 | - (void)testDoubleOverflow { 81 | YAJLParser *parser = [[YAJLParser alloc] init]; 82 | YAJLParserStatus status = [parser parse:[self loadData:@"overflow"]]; 83 | XCTAssertEqual(status, (NSUInteger)YAJLParserStatusError, @"Should have error status"); 84 | 85 | NSError *error = parser.parserError; 86 | if (error) { 87 | NSLog(@"Parse error:\n%@", error); 88 | XCTAssertEqual([error code], (NSInteger)YAJLParserErrorCodeDoubleOverflow); 89 | XCTAssertEqualObjects([error userInfo][YAJLParserValueKey], @"1.79769e+309"); 90 | } else { 91 | XCTFail(@"Should have error"); 92 | } 93 | } 94 | 95 | - (void)testLongLongOverflow { 96 | YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:YAJLParserOptionsStrictPrecision]; 97 | #if TARGET_OS_IPHONE 98 | YAJLParserStatus status = [parser parse:[self loadData:@"overflow_longlong"]]; 99 | #else 100 | YAJLParserStatus status = [parser parse:[self loadData:@"overflow_longlong_macosx"]]; 101 | #endif 102 | XCTAssertEqual(status, (NSUInteger)YAJLParserStatusError, @"Should have error status"); 103 | 104 | NSError *error = parser.parserError; 105 | if (error) { 106 | NSLog(@"Parse error:\n%@", error); 107 | XCTAssertEqual([error code], (NSInteger)YAJLParserErrorCodeIntegerOverflow); 108 | XCTAssertEqualObjects([error userInfo][YAJLParserValueKey], @"9223372036854775808"); 109 | } else { 110 | XCTFail(@"Should have error"); 111 | } 112 | } 113 | 114 | - (void)testOverflow2 { 115 | YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:0]; 116 | YAJLParserStatus status = [parser parse:[self loadData:@"overflow2"]]; 117 | XCTAssertTrue(status == YAJLParserStatusOK, @"Should have ok status"); 118 | } 119 | 120 | - (void)testStreaming { 121 | YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:0]; 122 | YAJLParserStatus status; 123 | status = [parser parse:[self loadData:@"stream1"]]; 124 | XCTAssertTrue(status == YAJLParserStatusOK, @"Should not have insufficient data"); 125 | 126 | status = [parser parse:[self loadData:@"stream2"]]; 127 | XCTAssertTrue(status == YAJLParserStatusOK, @"Should have finished"); 128 | } 129 | 130 | // TODO(gabe): Should error if you try to re-use 131 | - (void)_testParseMoreThanOnce { 132 | YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:0]; 133 | parser.delegate = self; 134 | YAJLParserStatus status; 135 | status = [parser parse:[self loadData:@"example"]]; 136 | XCTAssertTrue(status == YAJLParserStatusOK, @"Should be OK"); 137 | status = [parser parse:[self loadData:@"example"]]; 138 | XCTAssertTrue(status == YAJLParserStatusError, @"Should error"); 139 | } 140 | 141 | @end -------------------------------------------------------------------------------- /Tests/YAJLTestCase.h: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLTestCase.h 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 6/30/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | #import "YAJLParser.h" 11 | 12 | @interface YAJLTestCase : XCTestCase {} 13 | 14 | - (NSData *)loadData:(NSString *)name; 15 | - (NSString *)loadString:(NSString *)name; 16 | - (NSString *)directoryWithPath:(NSString *)path; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Tests/YAJLTestCase.m: -------------------------------------------------------------------------------- 1 | // 2 | // YAJLTestCase.m 3 | // YAJL 4 | // 5 | // Created by Gabriel Handford on 6/30/09. 6 | // Copyright 2009. All rights reserved. 7 | // 8 | 9 | #import "YAJLTestCase.h" 10 | 11 | 12 | @implementation YAJLTestCase 13 | 14 | - (NSData *)loadData:(NSString *)name { 15 | NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:name ofType:@"json"]; 16 | XCTAssertNotNil(path, @"Invalid name for load data"); 17 | return [NSData dataWithContentsOfFile:path options:NSUncachedRead error:nil]; 18 | } 19 | 20 | - (NSString *)loadString:(NSString *)name { 21 | return [[NSString alloc] initWithData:[self loadData:name] encoding:NSUTF8StringEncoding]; 22 | } 23 | 24 | - (NSString *)directoryWithPath:(NSString *)path { 25 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 26 | NSString *fullPath = [paths.lastObject stringByAppendingPathComponent:path]; 27 | NSLog(@"Using path: %@", fullPath); 28 | return fullPath; 29 | } 30 | 31 | 32 | - (void)parserDidStartDictionary:(YAJLParser *)parser { NSLog(@"{"); } 33 | - (void)parserDidEndDictionary:(YAJLParser *)parser { NSLog(@"}"); } 34 | 35 | - (void)parserDidStartArray:(YAJLParser *)parser { NSLog(@"["); } 36 | - (void)parserDidEndArray:(YAJLParser *)parser { NSLog(@"]"); } 37 | 38 | - (void)parser:(YAJLParser *)parser didMapKey:(NSString *)key { NSLog(@"'%@':", key); } 39 | - (void)parser:(YAJLParser *)parser didAdd:(id)value { NSLog(@"%@", [value description]); } 40 | 41 | @end -------------------------------------------------------------------------------- /YAJL.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /YAJL.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /YAJL.xcodeproj/xcshareddata/xcschemes/YAJL Library.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /YAJLO.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "YAJLO" 3 | s.version = "0.3.4" 4 | s.summary = "Objective-C bindings for YAJL (Yet Another JSON Library) C library" 5 | s.homepage = "http://lloyd.github.com/yajl" 6 | s.license = 'MIT' 7 | s.author = { "Gabriel Handford" => "gabrielh@gmail.com", "David Hart" => "david@hartbit.com" } 8 | s.source = { :git => "https://github.com/gabriel/yajl-objc.git", :tag => s.version.to_s } 9 | s.source_files = 'Classes/*.{h,m}', 'yajl-2.1.0/*.{h,c}', 'yajl-2.1.0/api/*.h' 10 | s.public_header_files = 'Classes/*.h' 11 | s.requires_arc = true 12 | s.ios.deployment_target = "7.0" 13 | s.osx.deployment_target = "10.9" 14 | end 15 | -------------------------------------------------------------------------------- /yajl-2.1.0/api/yajl_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __YAJL_COMMON_H__ 18 | #define __YAJL_COMMON_H__ 19 | 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #define YAJL_MAX_DEPTH 128 27 | 28 | /* msft dll export gunk. To build a DLL on windows, you 29 | * must define WIN32, YAJL_SHARED, and YAJL_BUILD. To use a shared 30 | * DLL, you must define YAJL_SHARED and WIN32 */ 31 | #if (defined(_WIN32) || defined(WIN32)) && defined(YAJL_SHARED) 32 | # ifdef YAJL_BUILD 33 | # define YAJL_API __declspec(dllexport) 34 | # else 35 | # define YAJL_API __declspec(dllimport) 36 | # endif 37 | #else 38 | # if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303 39 | # define YAJL_API __attribute__ ((visibility("default"))) 40 | # else 41 | # define YAJL_API 42 | # endif 43 | #endif 44 | 45 | /** pointer to a malloc function, supporting client overriding memory 46 | * allocation routines */ 47 | typedef void * (*yajl_malloc_func)(void *ctx, size_t sz); 48 | 49 | /** pointer to a free function, supporting client overriding memory 50 | * allocation routines */ 51 | typedef void (*yajl_free_func)(void *ctx, void * ptr); 52 | 53 | /** pointer to a realloc function which can resize an allocation. */ 54 | typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, size_t sz); 55 | 56 | /** A structure which can be passed to yajl_*_alloc routines to allow the 57 | * client to specify memory allocation functions to be used. */ 58 | typedef struct 59 | { 60 | /** pointer to a function that can allocate uninitialized memory */ 61 | yajl_malloc_func malloc; 62 | /** pointer to a function that can resize memory allocations */ 63 | yajl_realloc_func realloc; 64 | /** pointer to a function that can free memory allocated using 65 | * reallocFunction or mallocFunction */ 66 | yajl_free_func free; 67 | /** a context pointer that will be passed to above allocation routines */ 68 | void * ctx; 69 | } yajl_alloc_funcs; 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /yajl-2.1.0/api/yajl_gen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * \file yajl_gen.h 19 | * Interface to YAJL's JSON generation facilities. 20 | */ 21 | 22 | #include "yajl_common.h" 23 | 24 | #ifndef __YAJL_GEN_H__ 25 | #define __YAJL_GEN_H__ 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | /** generator status codes */ 33 | typedef enum { 34 | /** no error */ 35 | yajl_gen_status_ok = 0, 36 | /** at a point where a map key is generated, a function other than 37 | * yajl_gen_string was called */ 38 | yajl_gen_keys_must_be_strings, 39 | /** YAJL's maximum generation depth was exceeded. see 40 | * YAJL_MAX_DEPTH */ 41 | yajl_max_depth_exceeded, 42 | /** A generator function (yajl_gen_XXX) was called while in an error 43 | * state */ 44 | yajl_gen_in_error_state, 45 | /** A complete JSON document has been generated */ 46 | yajl_gen_generation_complete, 47 | /** yajl_gen_double was passed an invalid floating point value 48 | * (infinity or NaN). */ 49 | yajl_gen_invalid_number, 50 | /** A print callback was passed in, so there is no internal 51 | * buffer to get from */ 52 | yajl_gen_no_buf, 53 | /** returned from yajl_gen_string() when the yajl_gen_validate_utf8 54 | * option is enabled and an invalid was passed by client code. 55 | */ 56 | yajl_gen_invalid_string 57 | } yajl_gen_status; 58 | 59 | /** an opaque handle to a generator */ 60 | typedef struct yajl_gen_t * yajl_gen; 61 | 62 | /** a callback used for "printing" the results. */ 63 | typedef void (*yajl_print_t)(void * ctx, 64 | const char * str, 65 | size_t len); 66 | 67 | /** configuration parameters for the parser, these may be passed to 68 | * yajl_gen_config() along with option specific argument(s). In general, 69 | * all configuration parameters default to *off*. */ 70 | typedef enum { 71 | /** generate indented (beautiful) output */ 72 | yajl_gen_beautify = 0x01, 73 | /** 74 | * Set an indent string which is used when yajl_gen_beautify 75 | * is enabled. Maybe something like \\t or some number of 76 | * spaces. The default is four spaces ' '. 77 | */ 78 | yajl_gen_indent_string = 0x02, 79 | /** 80 | * Set a function and context argument that should be used to 81 | * output generated json. the function should conform to the 82 | * yajl_print_t prototype while the context argument is a 83 | * void * of your choosing. 84 | * 85 | * example: 86 | * yajl_gen_config(g, yajl_gen_print_callback, myFunc, myVoidPtr); 87 | */ 88 | yajl_gen_print_callback = 0x04, 89 | /** 90 | * Normally the generator does not validate that strings you 91 | * pass to it via yajl_gen_string() are valid UTF8. Enabling 92 | * this option will cause it to do so. 93 | */ 94 | yajl_gen_validate_utf8 = 0x08, 95 | /** 96 | * the forward solidus (slash or '/' in human) is not required to be 97 | * escaped in json text. By default, YAJL will not escape it in the 98 | * iterest of saving bytes. Setting this flag will cause YAJL to 99 | * always escape '/' in generated JSON strings. 100 | */ 101 | yajl_gen_escape_solidus = 0x10 102 | } yajl_gen_option; 103 | 104 | /** allow the modification of generator options subsequent to handle 105 | * allocation (via yajl_alloc) 106 | * \returns zero in case of errors, non-zero otherwise 107 | */ 108 | YAJL_API int yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...); 109 | 110 | /** allocate a generator handle 111 | * \param allocFuncs an optional pointer to a structure which allows 112 | * the client to overide the memory allocation 113 | * used by yajl. May be NULL, in which case 114 | * malloc/free/realloc will be used. 115 | * 116 | * \returns an allocated handle on success, NULL on failure (bad params) 117 | */ 118 | YAJL_API yajl_gen yajl_gen_alloc(const yajl_alloc_funcs * allocFuncs); 119 | 120 | /** free a generator handle */ 121 | YAJL_API void yajl_gen_free(yajl_gen handle); 122 | 123 | YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long long int number); 124 | /** generate a floating point number. number may not be infinity or 125 | * NaN, as these have no representation in JSON. In these cases the 126 | * generator will return 'yajl_gen_invalid_number' */ 127 | YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number); 128 | YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand, 129 | const char * num, 130 | size_t len); 131 | YAJL_API yajl_gen_status yajl_gen_string(yajl_gen hand, 132 | const unsigned char * str, 133 | size_t len); 134 | YAJL_API yajl_gen_status yajl_gen_null(yajl_gen hand); 135 | YAJL_API yajl_gen_status yajl_gen_bool(yajl_gen hand, int boolean); 136 | YAJL_API yajl_gen_status yajl_gen_map_open(yajl_gen hand); 137 | YAJL_API yajl_gen_status yajl_gen_map_close(yajl_gen hand); 138 | YAJL_API yajl_gen_status yajl_gen_array_open(yajl_gen hand); 139 | YAJL_API yajl_gen_status yajl_gen_array_close(yajl_gen hand); 140 | 141 | /** access the null terminated generator buffer. If incrementally 142 | * outputing JSON, one should call yajl_gen_clear to clear the 143 | * buffer. This allows stream generation. */ 144 | YAJL_API yajl_gen_status yajl_gen_get_buf(yajl_gen hand, 145 | const unsigned char ** buf, 146 | size_t * len); 147 | 148 | /** clear yajl's output buffer, but maintain all internal generation 149 | * state. This function will not "reset" the generator state, and is 150 | * intended to enable incremental JSON outputing. */ 151 | YAJL_API void yajl_gen_clear(yajl_gen hand); 152 | 153 | /** Reset the generator state. Allows a client to generate multiple 154 | * json entities in a stream. The "sep" string will be inserted to 155 | * separate the previously generated entity from the current, 156 | * NULL means *no separation* of entites (clients beware, generating 157 | * multiple JSON numbers, for instance, will result in inscrutable 158 | * output) */ 159 | YAJL_API void yajl_gen_reset(yajl_gen hand, const char * sep); 160 | 161 | #ifdef __cplusplus 162 | } 163 | #endif 164 | 165 | #endif 166 | -------------------------------------------------------------------------------- /yajl-2.1.0/api/yajl_parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * \file yajl_parse.h 19 | * Interface to YAJL's JSON stream parsing facilities. 20 | */ 21 | 22 | #include "yajl_common.h" 23 | 24 | #ifndef __YAJL_PARSE_H__ 25 | #define __YAJL_PARSE_H__ 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | /** error codes returned from this interface */ 33 | typedef enum { 34 | /** no error was encountered */ 35 | yajl_status_ok, 36 | /** a client callback returned zero, stopping the parse */ 37 | yajl_status_client_canceled, 38 | /** An error occured during the parse. Call yajl_get_error for 39 | * more information about the encountered error */ 40 | yajl_status_error 41 | } yajl_status; 42 | 43 | /** attain a human readable, english, string for an error */ 44 | YAJL_API const char * yajl_status_to_string(yajl_status code); 45 | 46 | /** an opaque handle to a parser */ 47 | typedef struct yajl_handle_t * yajl_handle; 48 | 49 | /** yajl is an event driven parser. this means as json elements are 50 | * parsed, you are called back to do something with the data. The 51 | * functions in this table indicate the various events for which 52 | * you will be called back. Each callback accepts a "context" 53 | * pointer, this is a void * that is passed into the yajl_parse 54 | * function which the client code may use to pass around context. 55 | * 56 | * All callbacks return an integer. If non-zero, the parse will 57 | * continue. If zero, the parse will be canceled and 58 | * yajl_status_client_canceled will be returned from the parse. 59 | * 60 | * \attention { 61 | * A note about the handling of numbers: 62 | * 63 | * yajl will only convert numbers that can be represented in a 64 | * double or a 64 bit (long long) int. All other numbers will 65 | * be passed to the client in string form using the yajl_number 66 | * callback. Furthermore, if yajl_number is not NULL, it will 67 | * always be used to return numbers, that is yajl_integer and 68 | * yajl_double will be ignored. If yajl_number is NULL but one 69 | * of yajl_integer or yajl_double are defined, parsing of a 70 | * number larger than is representable in a double or 64 bit 71 | * integer will result in a parse error. 72 | * } 73 | */ 74 | typedef struct { 75 | int (* yajl_null)(void * ctx); 76 | int (* yajl_boolean)(void * ctx, int boolVal); 77 | int (* yajl_integer)(void * ctx, long long integerVal); 78 | int (* yajl_double)(void * ctx, double doubleVal); 79 | /** A callback which passes the string representation of the number 80 | * back to the client. Will be used for all numbers when present */ 81 | int (* yajl_number)(void * ctx, const char * numberVal, 82 | size_t numberLen); 83 | 84 | /** strings are returned as pointers into the JSON text when, 85 | * possible, as a result, they are _not_ null padded */ 86 | int (* yajl_string)(void * ctx, const unsigned char * stringVal, 87 | size_t stringLen); 88 | 89 | int (* yajl_start_map)(void * ctx); 90 | int (* yajl_map_key)(void * ctx, const unsigned char * key, 91 | size_t stringLen); 92 | int (* yajl_end_map)(void * ctx); 93 | 94 | int (* yajl_start_array)(void * ctx); 95 | int (* yajl_end_array)(void * ctx); 96 | } yajl_callbacks; 97 | 98 | /** allocate a parser handle 99 | * \param callbacks a yajl callbacks structure specifying the 100 | * functions to call when different JSON entities 101 | * are encountered in the input text. May be NULL, 102 | * which is only useful for validation. 103 | * \param afs memory allocation functions, may be NULL for to use 104 | * C runtime library routines (malloc and friends) 105 | * \param ctx a context pointer that will be passed to callbacks. 106 | */ 107 | YAJL_API yajl_handle yajl_alloc(const yajl_callbacks * callbacks, 108 | yajl_alloc_funcs * afs, 109 | void * ctx); 110 | 111 | 112 | /** configuration parameters for the parser, these may be passed to 113 | * yajl_config() along with option specific argument(s). In general, 114 | * all configuration parameters default to *off*. */ 115 | typedef enum { 116 | /** Ignore javascript style comments present in 117 | * JSON input. Non-standard, but rather fun 118 | * arguments: toggled off with integer zero, on otherwise. 119 | * 120 | * example: 121 | * yajl_config(h, yajl_allow_comments, 1); // turn comment support on 122 | */ 123 | yajl_allow_comments = 0x01, 124 | /** 125 | * When set the parser will verify that all strings in JSON input are 126 | * valid UTF8 and will emit a parse error if this is not so. When set, 127 | * this option makes parsing slightly more expensive (~7% depending 128 | * on processor and compiler in use) 129 | * 130 | * example: 131 | * yajl_config(h, yajl_dont_validate_strings, 1); // disable utf8 checking 132 | */ 133 | yajl_dont_validate_strings = 0x02, 134 | /** 135 | * By default, upon calls to yajl_complete_parse(), yajl will 136 | * ensure the entire input text was consumed and will raise an error 137 | * otherwise. Enabling this flag will cause yajl to disable this 138 | * check. This can be useful when parsing json out of a that contains more 139 | * than a single JSON document. 140 | */ 141 | yajl_allow_trailing_garbage = 0x04, 142 | /** 143 | * Allow multiple values to be parsed by a single handle. The 144 | * entire text must be valid JSON, and values can be seperated 145 | * by any kind of whitespace. This flag will change the 146 | * behavior of the parser, and cause it continue parsing after 147 | * a value is parsed, rather than transitioning into a 148 | * complete state. This option can be useful when parsing multiple 149 | * values from an input stream. 150 | */ 151 | yajl_allow_multiple_values = 0x08, 152 | /** 153 | * When yajl_complete_parse() is called the parser will 154 | * check that the top level value was completely consumed. I.E., 155 | * if called whilst in the middle of parsing a value 156 | * yajl will enter an error state (premature EOF). Setting this 157 | * flag suppresses that check and the corresponding error. 158 | */ 159 | yajl_allow_partial_values = 0x10 160 | } yajl_option; 161 | 162 | /** allow the modification of parser options subsequent to handle 163 | * allocation (via yajl_alloc) 164 | * \returns zero in case of errors, non-zero otherwise 165 | */ 166 | YAJL_API int yajl_config(yajl_handle h, yajl_option opt, ...); 167 | 168 | /** free a parser handle */ 169 | YAJL_API void yajl_free(yajl_handle handle); 170 | 171 | /** Parse some json! 172 | * \param hand - a handle to the json parser allocated with yajl_alloc 173 | * \param jsonText - a pointer to the UTF8 json text to be parsed 174 | * \param jsonTextLength - the length, in bytes, of input text 175 | */ 176 | YAJL_API yajl_status yajl_parse(yajl_handle hand, 177 | const unsigned char * jsonText, 178 | size_t jsonTextLength); 179 | 180 | /** Parse any remaining buffered json. 181 | * Since yajl is a stream-based parser, without an explicit end of 182 | * input, yajl sometimes can't decide if content at the end of the 183 | * stream is valid or not. For example, if "1" has been fed in, 184 | * yajl can't know whether another digit is next or some character 185 | * that would terminate the integer token. 186 | * 187 | * \param hand - a handle to the json parser allocated with yajl_alloc 188 | */ 189 | YAJL_API yajl_status yajl_complete_parse(yajl_handle hand); 190 | 191 | /** get an error string describing the state of the 192 | * parse. 193 | * 194 | * If verbose is non-zero, the message will include the JSON 195 | * text where the error occured, along with an arrow pointing to 196 | * the specific char. 197 | * 198 | * \returns A dynamically allocated string will be returned which should 199 | * be freed with yajl_free_error 200 | */ 201 | YAJL_API unsigned char * yajl_get_error(yajl_handle hand, int verbose, 202 | const unsigned char * jsonText, 203 | size_t jsonTextLength); 204 | 205 | /** 206 | * get the amount of data consumed from the last chunk passed to YAJL. 207 | * 208 | * In the case of a successful parse this can help you understand if 209 | * the entire buffer was consumed (which will allow you to handle 210 | * "junk at end of input"). 211 | * 212 | * In the event an error is encountered during parsing, this function 213 | * affords the client a way to get the offset into the most recent 214 | * chunk where the error occured. 0 will be returned if no error 215 | * was encountered. 216 | */ 217 | YAJL_API size_t yajl_get_bytes_consumed(yajl_handle hand); 218 | 219 | /** free an error returned from yajl_get_error */ 220 | YAJL_API void yajl_free_error(yajl_handle hand, unsigned char * str); 221 | 222 | #ifdef __cplusplus 223 | } 224 | #endif 225 | 226 | #endif 227 | -------------------------------------------------------------------------------- /yajl-2.1.0/api/yajl_tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011 Florian Forster 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * \file yajl_tree.h 19 | * 20 | * Parses JSON data and returns the data in tree form. 21 | * 22 | * \author Florian Forster 23 | * \date August 2010 24 | * 25 | * This interface makes quick parsing and extraction of 26 | * smallish JSON docs trivial: 27 | * 28 | * \include example/parse_config.c 29 | */ 30 | 31 | #ifndef YAJL_TREE_H 32 | #define YAJL_TREE_H 1 33 | 34 | #include "yajl_common.h" 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | /** possible data types that a yajl_val_s can hold */ 41 | typedef enum { 42 | yajl_t_string = 1, 43 | yajl_t_number = 2, 44 | yajl_t_object = 3, 45 | yajl_t_array = 4, 46 | yajl_t_true = 5, 47 | yajl_t_false = 6, 48 | yajl_t_null = 7, 49 | /** The any type isn't valid for yajl_val_s.type, but can be 50 | * used as an argument to routines like yajl_tree_get(). 51 | */ 52 | yajl_t_any = 8 53 | } yajl_type; 54 | 55 | #define YAJL_NUMBER_INT_VALID 0x01 56 | #define YAJL_NUMBER_DOUBLE_VALID 0x02 57 | 58 | /** A pointer to a node in the parse tree */ 59 | typedef struct yajl_val_s * yajl_val; 60 | 61 | /** 62 | * A JSON value representation capable of holding one of the seven 63 | * types above. For "string", "number", "object", and "array" 64 | * additional data is available in the union. The "YAJL_IS_*" 65 | * and "YAJL_GET_*" macros below allow type checking and convenient 66 | * value extraction. 67 | */ 68 | struct yajl_val_s 69 | { 70 | /** Type of the value contained. Use the "YAJL_IS_*" macros to check for a 71 | * specific type. */ 72 | yajl_type type; 73 | /** Type-specific data. You may use the "YAJL_GET_*" macros to access these 74 | * members. */ 75 | union 76 | { 77 | char * string; 78 | struct { 79 | long long i; /*< integer value, if representable. */ 80 | double d; /*< double value, if representable. */ 81 | char *r; /*< unparsed number in string form. */ 82 | /** Signals whether the \em i and \em d members are 83 | * valid. See \c YAJL_NUMBER_INT_VALID and 84 | * \c YAJL_NUMBER_DOUBLE_VALID. */ 85 | unsigned int flags; 86 | } number; 87 | struct { 88 | const char **keys; /*< Array of keys */ 89 | yajl_val *values; /*< Array of values. */ 90 | size_t len; /*< Number of key-value-pairs. */ 91 | } object; 92 | struct { 93 | yajl_val *values; /*< Array of elements. */ 94 | size_t len; /*< Number of elements. */ 95 | } array; 96 | } u; 97 | }; 98 | 99 | /** 100 | * Parse a string. 101 | * 102 | * Parses an null-terminated string containing JSON data and returns a pointer 103 | * to the top-level value (root of the parse tree). 104 | * 105 | * \param input Pointer to a null-terminated utf8 string containing 106 | * JSON data. 107 | * \param error_buffer Pointer to a buffer in which an error message will 108 | * be stored if \em yajl_tree_parse fails, or 109 | * \c NULL. The buffer will be initialized before 110 | * parsing, so its content will be destroyed even if 111 | * \em yajl_tree_parse succeeds. 112 | * \param error_buffer_size Size of the memory area pointed to by 113 | * \em error_buffer_size. If \em error_buffer_size is 114 | * \c NULL, this argument is ignored. 115 | * 116 | * \returns Pointer to the top-level value or \c NULL on error. The memory 117 | * pointed to must be freed using \em yajl_tree_free. In case of an error, a 118 | * null terminated message describing the error in more detail is stored in 119 | * \em error_buffer if it is not \c NULL. 120 | */ 121 | YAJL_API yajl_val yajl_tree_parse (const char *input, 122 | char *error_buffer, size_t error_buffer_size); 123 | 124 | 125 | /** 126 | * Free a parse tree returned by "yajl_tree_parse". 127 | * 128 | * \param v Pointer to a JSON value returned by "yajl_tree_parse". Passing NULL 129 | * is valid and results in a no-op. 130 | */ 131 | YAJL_API void yajl_tree_free (yajl_val v); 132 | 133 | /** 134 | * Access a nested value inside a tree. 135 | * 136 | * \param parent the node under which you'd like to extract values. 137 | * \param path A null terminated array of strings, each the name of an object key 138 | * \param type the yajl_type of the object you seek, or yajl_t_any if any will do. 139 | * 140 | * \returns a pointer to the found value, or NULL if we came up empty. 141 | * 142 | * Future Ideas: it'd be nice to move path to a string and implement support for 143 | * a teeny tiny micro language here, so you can extract array elements, do things 144 | * like .first and .last, even .length. Inspiration from JSONPath and css selectors? 145 | * No it wouldn't be fast, but that's not what this API is about. 146 | */ 147 | YAJL_API yajl_val yajl_tree_get(yajl_val parent, const char ** path, yajl_type type); 148 | 149 | /* Various convenience macros to check the type of a `yajl_val` */ 150 | #define YAJL_IS_STRING(v) (((v) != NULL) && ((v)->type == yajl_t_string)) 151 | #define YAJL_IS_NUMBER(v) (((v) != NULL) && ((v)->type == yajl_t_number)) 152 | #define YAJL_IS_INTEGER(v) (YAJL_IS_NUMBER(v) && ((v)->u.number.flags & YAJL_NUMBER_INT_VALID)) 153 | #define YAJL_IS_DOUBLE(v) (YAJL_IS_NUMBER(v) && ((v)->u.number.flags & YAJL_NUMBER_DOUBLE_VALID)) 154 | #define YAJL_IS_OBJECT(v) (((v) != NULL) && ((v)->type == yajl_t_object)) 155 | #define YAJL_IS_ARRAY(v) (((v) != NULL) && ((v)->type == yajl_t_array )) 156 | #define YAJL_IS_TRUE(v) (((v) != NULL) && ((v)->type == yajl_t_true )) 157 | #define YAJL_IS_FALSE(v) (((v) != NULL) && ((v)->type == yajl_t_false )) 158 | #define YAJL_IS_NULL(v) (((v) != NULL) && ((v)->type == yajl_t_null )) 159 | 160 | /** Given a yajl_val_string return a ptr to the bare string it contains, 161 | * or NULL if the value is not a string. */ 162 | #define YAJL_GET_STRING(v) (YAJL_IS_STRING(v) ? (v)->u.string : NULL) 163 | 164 | /** Get the string representation of a number. You should check type first, 165 | * perhaps using YAJL_IS_NUMBER */ 166 | #define YAJL_GET_NUMBER(v) ((v)->u.number.r) 167 | 168 | /** Get the double representation of a number. You should check type first, 169 | * perhaps using YAJL_IS_DOUBLE */ 170 | #define YAJL_GET_DOUBLE(v) ((v)->u.number.d) 171 | 172 | /** Get the 64bit (long long) integer representation of a number. You should 173 | * check type first, perhaps using YAJL_IS_INTEGER */ 174 | #define YAJL_GET_INTEGER(v) ((v)->u.number.i) 175 | 176 | /** Get a pointer to a yajl_val_object or NULL if the value is not an object. */ 177 | #define YAJL_GET_OBJECT(v) (YAJL_IS_OBJECT(v) ? &(v)->u.object : NULL) 178 | 179 | /** Get a pointer to a yajl_val_array or NULL if the value is not an object. */ 180 | #define YAJL_GET_ARRAY(v) (YAJL_IS_ARRAY(v) ? &(v)->u.array : NULL) 181 | 182 | #ifdef __cplusplus 183 | } 184 | #endif 185 | 186 | #endif /* YAJL_TREE_H */ 187 | -------------------------------------------------------------------------------- /yajl-2.1.0/api/yajl_version.h: -------------------------------------------------------------------------------- 1 | #ifndef YAJL_VERSION_H_ 2 | #define YAJL_VERSION_H_ 3 | 4 | #include "yajl_common.h" 5 | 6 | #define YAJL_MAJOR 2 7 | #define YAJL_MINOR 1 8 | #define YAJL_MICRO 0 9 | 10 | #define YAJL_VERSION ((YAJL_MAJOR * 10000) + (YAJL_MINOR * 100) + YAJL_MICRO) 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | extern int YAJL_API yajl_version(void); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif /* YAJL_VERSION_H_ */ 23 | 24 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "api/yajl_parse.h" 18 | #include "yajl_lex.h" 19 | #include "yajl_parser.h" 20 | #include "yajl_alloc.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | const char * 28 | yajl_status_to_string(yajl_status stat) 29 | { 30 | const char * statStr = "unknown"; 31 | switch (stat) { 32 | case yajl_status_ok: 33 | statStr = "ok, no error"; 34 | break; 35 | case yajl_status_client_canceled: 36 | statStr = "client canceled parse"; 37 | break; 38 | case yajl_status_error: 39 | statStr = "parse error"; 40 | break; 41 | } 42 | return statStr; 43 | } 44 | 45 | yajl_handle 46 | yajl_alloc(const yajl_callbacks * callbacks, 47 | yajl_alloc_funcs * afs, 48 | void * ctx) 49 | { 50 | yajl_handle hand = NULL; 51 | yajl_alloc_funcs afsBuffer; 52 | 53 | /* first order of business is to set up memory allocation routines */ 54 | if (afs != NULL) { 55 | if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) 56 | { 57 | return NULL; 58 | } 59 | } else { 60 | yajl_set_default_alloc_funcs(&afsBuffer); 61 | afs = &afsBuffer; 62 | } 63 | 64 | hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t)); 65 | 66 | /* copy in pointers to allocation routines */ 67 | memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); 68 | 69 | hand->callbacks = callbacks; 70 | hand->ctx = ctx; 71 | hand->lexer = NULL; 72 | hand->bytesConsumed = 0; 73 | hand->decodeBuf = yajl_buf_alloc(&(hand->alloc)); 74 | hand->flags = 0; 75 | yajl_bs_init(hand->stateStack, &(hand->alloc)); 76 | yajl_bs_push(hand->stateStack, yajl_state_start); 77 | 78 | return hand; 79 | } 80 | 81 | int 82 | yajl_config(yajl_handle h, yajl_option opt, ...) 83 | { 84 | int rv = 1; 85 | va_list ap; 86 | va_start(ap, opt); 87 | 88 | switch(opt) { 89 | case yajl_allow_comments: 90 | case yajl_dont_validate_strings: 91 | case yajl_allow_trailing_garbage: 92 | case yajl_allow_multiple_values: 93 | case yajl_allow_partial_values: 94 | if (va_arg(ap, int)) h->flags |= opt; 95 | else h->flags &= ~opt; 96 | break; 97 | default: 98 | rv = 0; 99 | } 100 | va_end(ap); 101 | 102 | return rv; 103 | } 104 | 105 | void 106 | yajl_free(yajl_handle handle) 107 | { 108 | yajl_bs_free(handle->stateStack); 109 | yajl_buf_free(handle->decodeBuf); 110 | if (handle->lexer) { 111 | yajl_lex_free(handle->lexer); 112 | handle->lexer = NULL; 113 | } 114 | YA_FREE(&(handle->alloc), handle); 115 | } 116 | 117 | yajl_status 118 | yajl_parse(yajl_handle hand, const unsigned char * jsonText, 119 | size_t jsonTextLen) 120 | { 121 | yajl_status status; 122 | 123 | /* lazy allocation of the lexer */ 124 | if (hand->lexer == NULL) { 125 | hand->lexer = yajl_lex_alloc(&(hand->alloc), 126 | hand->flags & yajl_allow_comments, 127 | !(hand->flags & yajl_dont_validate_strings)); 128 | } 129 | 130 | status = yajl_do_parse(hand, jsonText, jsonTextLen); 131 | return status; 132 | } 133 | 134 | 135 | yajl_status 136 | yajl_complete_parse(yajl_handle hand) 137 | { 138 | /* The lexer is lazy allocated in the first call to parse. if parse is 139 | * never called, then no data was provided to parse at all. This is a 140 | * "premature EOF" error unless yajl_allow_partial_values is specified. 141 | * allocating the lexer now is the simplest possible way to handle this 142 | * case while preserving all the other semantics of the parser 143 | * (multiple values, partial values, etc). */ 144 | if (hand->lexer == NULL) { 145 | hand->lexer = yajl_lex_alloc(&(hand->alloc), 146 | hand->flags & yajl_allow_comments, 147 | !(hand->flags & yajl_dont_validate_strings)); 148 | } 149 | 150 | return yajl_do_finish(hand); 151 | } 152 | 153 | unsigned char * 154 | yajl_get_error(yajl_handle hand, int verbose, 155 | const unsigned char * jsonText, size_t jsonTextLen) 156 | { 157 | return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose); 158 | } 159 | 160 | size_t 161 | yajl_get_bytes_consumed(yajl_handle hand) 162 | { 163 | if (!hand) return 0; 164 | else return hand->bytesConsumed; 165 | } 166 | 167 | 168 | void 169 | yajl_free_error(yajl_handle hand, unsigned char * str) 170 | { 171 | /* use memory allocation functions if set */ 172 | YA_FREE(&(hand->alloc), str); 173 | } 174 | 175 | /* XXX: add utility routines to parse from file */ 176 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_alloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * \file yajl_alloc.h 19 | * default memory allocation routines for yajl which use malloc/realloc and 20 | * free 21 | */ 22 | 23 | #include "yajl_alloc.h" 24 | #include 25 | 26 | static void * yajl_internal_malloc(void *ctx, size_t sz) 27 | { 28 | (void)ctx; 29 | return malloc(sz); 30 | } 31 | 32 | static void * yajl_internal_realloc(void *ctx, void * previous, 33 | size_t sz) 34 | { 35 | (void)ctx; 36 | return realloc(previous, sz); 37 | } 38 | 39 | static void yajl_internal_free(void *ctx, void * ptr) 40 | { 41 | (void)ctx; 42 | free(ptr); 43 | } 44 | 45 | void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf) 46 | { 47 | yaf->malloc = yajl_internal_malloc; 48 | yaf->free = yajl_internal_free; 49 | yaf->realloc = yajl_internal_realloc; 50 | yaf->ctx = NULL; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * \file yajl_alloc.h 19 | * default memory allocation routines for yajl which use malloc/realloc and 20 | * free 21 | */ 22 | 23 | #ifndef __YAJL_ALLOC_H__ 24 | #define __YAJL_ALLOC_H__ 25 | 26 | #include "api/yajl_common.h" 27 | 28 | #define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz)) 29 | #define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr)) 30 | #define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz)) 31 | 32 | void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_buf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "yajl_buf.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define YAJL_BUF_INIT_SIZE 2048 24 | 25 | struct yajl_buf_t { 26 | size_t len; 27 | size_t used; 28 | unsigned char * data; 29 | yajl_alloc_funcs * alloc; 30 | }; 31 | 32 | static 33 | void yajl_buf_ensure_available(yajl_buf buf, size_t want) 34 | { 35 | size_t need; 36 | 37 | assert(buf != NULL); 38 | 39 | /* first call */ 40 | if (buf->data == NULL) { 41 | buf->len = YAJL_BUF_INIT_SIZE; 42 | buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len); 43 | buf->data[0] = 0; 44 | } 45 | 46 | need = buf->len; 47 | 48 | while (want >= (need - buf->used)) need <<= 1; 49 | 50 | if (need != buf->len) { 51 | buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need); 52 | buf->len = need; 53 | } 54 | } 55 | 56 | yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc) 57 | { 58 | yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t)); 59 | memset((void *) b, 0, sizeof(struct yajl_buf_t)); 60 | b->alloc = alloc; 61 | return b; 62 | } 63 | 64 | void yajl_buf_free(yajl_buf buf) 65 | { 66 | assert(buf != NULL); 67 | if (buf->data) YA_FREE(buf->alloc, buf->data); 68 | YA_FREE(buf->alloc, buf); 69 | } 70 | 71 | void yajl_buf_append(yajl_buf buf, const void * data, size_t len) 72 | { 73 | yajl_buf_ensure_available(buf, len); 74 | if (len > 0) { 75 | assert(data != NULL); 76 | memcpy(buf->data + buf->used, data, len); 77 | buf->used += len; 78 | buf->data[buf->used] = 0; 79 | } 80 | } 81 | 82 | void yajl_buf_clear(yajl_buf buf) 83 | { 84 | buf->used = 0; 85 | if (buf->data) buf->data[buf->used] = 0; 86 | } 87 | 88 | const unsigned char * yajl_buf_data(yajl_buf buf) 89 | { 90 | return buf->data; 91 | } 92 | 93 | size_t yajl_buf_len(yajl_buf buf) 94 | { 95 | return buf->used; 96 | } 97 | 98 | void 99 | yajl_buf_truncate(yajl_buf buf, size_t len) 100 | { 101 | assert(len <= buf->used); 102 | buf->used = len; 103 | } 104 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_buf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __YAJL_BUF_H__ 18 | #define __YAJL_BUF_H__ 19 | 20 | #include "api/yajl_common.h" 21 | #include "yajl_alloc.h" 22 | 23 | /* 24 | * Implementation/performance notes. If this were moved to a header 25 | * only implementation using #define's where possible we might be 26 | * able to sqeeze a little performance out of the guy by killing function 27 | * call overhead. YMMV. 28 | */ 29 | 30 | /** 31 | * yajl_buf is a buffer with exponential growth. the buffer ensures that 32 | * you are always null padded. 33 | */ 34 | typedef struct yajl_buf_t * yajl_buf; 35 | 36 | /* allocate a new buffer */ 37 | yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc); 38 | 39 | /* free the buffer */ 40 | void yajl_buf_free(yajl_buf buf); 41 | 42 | /* append a number of bytes to the buffer */ 43 | void yajl_buf_append(yajl_buf buf, const void * data, size_t len); 44 | 45 | /* empty the buffer */ 46 | void yajl_buf_clear(yajl_buf buf); 47 | 48 | /* get a pointer to the beginning of the buffer */ 49 | const unsigned char * yajl_buf_data(yajl_buf buf); 50 | 51 | /* get the length of the buffer */ 52 | size_t yajl_buf_len(yajl_buf buf); 53 | 54 | /* truncate the buffer */ 55 | void yajl_buf_truncate(yajl_buf buf, size_t len); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_bytestack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * A header only implementation of a simple stack of bytes, used in YAJL 19 | * to maintain parse state. 20 | */ 21 | 22 | #ifndef __YAJL_BYTESTACK_H__ 23 | #define __YAJL_BYTESTACK_H__ 24 | 25 | #include "api/yajl_common.h" 26 | 27 | #define YAJL_BS_INC 128 28 | 29 | typedef struct yajl_bytestack_t 30 | { 31 | unsigned char * stack; 32 | size_t size; 33 | size_t used; 34 | yajl_alloc_funcs * yaf; 35 | } yajl_bytestack; 36 | 37 | /* initialize a bytestack */ 38 | #define yajl_bs_init(obs, _yaf) { \ 39 | (obs).stack = NULL; \ 40 | (obs).size = 0; \ 41 | (obs).used = 0; \ 42 | (obs).yaf = (_yaf); \ 43 | } \ 44 | 45 | 46 | /* initialize a bytestack */ 47 | #define yajl_bs_free(obs) \ 48 | if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack); 49 | 50 | #define yajl_bs_current(obs) \ 51 | (assert((obs).used > 0), (obs).stack[(obs).used - 1]) 52 | 53 | #define yajl_bs_push(obs, byte) { \ 54 | if (((obs).size - (obs).used) == 0) { \ 55 | (obs).size += YAJL_BS_INC; \ 56 | (obs).stack = (obs).yaf->realloc((obs).yaf->ctx,\ 57 | (void *) (obs).stack, (obs).size);\ 58 | } \ 59 | (obs).stack[((obs).used)++] = (byte); \ 60 | } 61 | 62 | /* removes the top item of the stack, returns nothing */ 63 | #define yajl_bs_pop(obs) { ((obs).used)--; } 64 | 65 | #define yajl_bs_set(obs, byte) \ 66 | (obs).stack[((obs).used) - 1] = (byte); 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_encode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "yajl_encode.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | static void CharToHex(unsigned char c, char * hexBuf) 25 | { 26 | const char * hexchar = "0123456789ABCDEF"; 27 | hexBuf[0] = hexchar[c >> 4]; 28 | hexBuf[1] = hexchar[c & 0x0F]; 29 | } 30 | 31 | void 32 | yajl_string_encode(const yajl_print_t print, 33 | void * ctx, 34 | const unsigned char * str, 35 | size_t len, 36 | int escape_solidus) 37 | { 38 | size_t beg = 0; 39 | size_t end = 0; 40 | char hexBuf[7]; 41 | hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0'; 42 | hexBuf[6] = 0; 43 | 44 | while (end < len) { 45 | const char * escaped = NULL; 46 | switch (str[end]) { 47 | case '\r': escaped = "\\r"; break; 48 | case '\n': escaped = "\\n"; break; 49 | case '\\': escaped = "\\\\"; break; 50 | /* it is not required to escape a solidus in JSON: 51 | * read sec. 2.5: http://www.ietf.org/rfc/rfc4627.txt 52 | * specifically, this production from the grammar: 53 | * unescaped = %x20-21 / %x23-5B / %x5D-10FFFF 54 | */ 55 | case '/': if (escape_solidus) escaped = "\\/"; break; 56 | case '"': escaped = "\\\""; break; 57 | case '\f': escaped = "\\f"; break; 58 | case '\b': escaped = "\\b"; break; 59 | case '\t': escaped = "\\t"; break; 60 | default: 61 | if ((unsigned char) str[end] < 32) { 62 | CharToHex(str[end], hexBuf + 4); 63 | escaped = hexBuf; 64 | } 65 | break; 66 | } 67 | if (escaped != NULL) { 68 | print(ctx, (const char *) (str + beg), end - beg); 69 | print(ctx, escaped, (unsigned int)strlen(escaped)); 70 | beg = ++end; 71 | } else { 72 | ++end; 73 | } 74 | } 75 | print(ctx, (const char *) (str + beg), end - beg); 76 | } 77 | 78 | static void hexToDigit(unsigned int * val, const unsigned char * hex) 79 | { 80 | unsigned int i; 81 | for (i=0;i<4;i++) { 82 | unsigned char c = hex[i]; 83 | if (c >= 'A') c = (c & ~0x20) - 7; 84 | c -= '0'; 85 | assert(!(c & 0xF0)); 86 | *val = (*val << 4) | c; 87 | } 88 | } 89 | 90 | static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf) 91 | { 92 | if (codepoint < 0x80) { 93 | utf8Buf[0] = (char) codepoint; 94 | utf8Buf[1] = 0; 95 | } else if (codepoint < 0x0800) { 96 | utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0); 97 | utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80); 98 | utf8Buf[2] = 0; 99 | } else if (codepoint < 0x10000) { 100 | utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0); 101 | utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80); 102 | utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80); 103 | utf8Buf[3] = 0; 104 | } else if (codepoint < 0x200000) { 105 | utf8Buf[0] =(char)((codepoint >> 18) | 0xF0); 106 | utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80); 107 | utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80); 108 | utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80); 109 | utf8Buf[4] = 0; 110 | } else { 111 | utf8Buf[0] = '?'; 112 | utf8Buf[1] = 0; 113 | } 114 | } 115 | 116 | void yajl_string_decode(yajl_buf buf, const unsigned char * str, 117 | size_t len) 118 | { 119 | size_t beg = 0; 120 | size_t end = 0; 121 | 122 | while (end < len) { 123 | if (str[end] == '\\') { 124 | char utf8Buf[5]; 125 | const char * unescaped = "?"; 126 | yajl_buf_append(buf, str + beg, end - beg); 127 | switch (str[++end]) { 128 | case 'r': unescaped = "\r"; break; 129 | case 'n': unescaped = "\n"; break; 130 | case '\\': unescaped = "\\"; break; 131 | case '/': unescaped = "/"; break; 132 | case '"': unescaped = "\""; break; 133 | case 'f': unescaped = "\f"; break; 134 | case 'b': unescaped = "\b"; break; 135 | case 't': unescaped = "\t"; break; 136 | case 'u': { 137 | unsigned int codepoint = 0; 138 | hexToDigit(&codepoint, str + ++end); 139 | end+=3; 140 | /* check if this is a surrogate */ 141 | if ((codepoint & 0xFC00) == 0xD800) { 142 | end++; 143 | if (str[end] == '\\' && str[end + 1] == 'u') { 144 | unsigned int surrogate = 0; 145 | hexToDigit(&surrogate, str + end + 2); 146 | codepoint = 147 | (((codepoint & 0x3F) << 10) | 148 | ((((codepoint >> 6) & 0xF) + 1) << 16) | 149 | (surrogate & 0x3FF)); 150 | end += 5; 151 | } else { 152 | unescaped = "?"; 153 | break; 154 | } 155 | } 156 | 157 | Utf32toUtf8(codepoint, utf8Buf); 158 | unescaped = utf8Buf; 159 | 160 | if (codepoint == 0) { 161 | yajl_buf_append(buf, unescaped, 1); 162 | beg = ++end; 163 | continue; 164 | } 165 | 166 | break; 167 | } 168 | default: 169 | assert("this should never happen" == NULL); 170 | } 171 | yajl_buf_append(buf, unescaped, (unsigned int)strlen(unescaped)); 172 | beg = ++end; 173 | } else { 174 | end++; 175 | } 176 | } 177 | yajl_buf_append(buf, str + beg, end - beg); 178 | } 179 | 180 | #define ADV_PTR s++; if (!(len--)) return 0; 181 | 182 | int yajl_string_validate_utf8(const unsigned char * s, size_t len) 183 | { 184 | if (!len) return 1; 185 | if (!s) return 0; 186 | 187 | while (len--) { 188 | /* single byte */ 189 | if (*s <= 0x7f) { 190 | /* noop */ 191 | } 192 | /* two byte */ 193 | else if ((*s >> 5) == 0x6) { 194 | ADV_PTR; 195 | if (!((*s >> 6) == 0x2)) return 0; 196 | } 197 | /* three byte */ 198 | else if ((*s >> 4) == 0x0e) { 199 | ADV_PTR; 200 | if (!((*s >> 6) == 0x2)) return 0; 201 | ADV_PTR; 202 | if (!((*s >> 6) == 0x2)) return 0; 203 | } 204 | /* four byte */ 205 | else if ((*s >> 3) == 0x1e) { 206 | ADV_PTR; 207 | if (!((*s >> 6) == 0x2)) return 0; 208 | ADV_PTR; 209 | if (!((*s >> 6) == 0x2)) return 0; 210 | ADV_PTR; 211 | if (!((*s >> 6) == 0x2)) return 0; 212 | } else { 213 | return 0; 214 | } 215 | 216 | s++; 217 | } 218 | 219 | return 1; 220 | } 221 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_encode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __YAJL_ENCODE_H__ 18 | #define __YAJL_ENCODE_H__ 19 | 20 | #include "yajl_buf.h" 21 | #include "api/yajl_gen.h" 22 | 23 | void yajl_string_encode(const yajl_print_t printer, 24 | void * ctx, 25 | const unsigned char * str, 26 | size_t length, 27 | int escape_solidus); 28 | 29 | void yajl_string_decode(yajl_buf buf, const unsigned char * str, 30 | size_t length); 31 | 32 | int yajl_string_validate_utf8(const unsigned char * s, size_t len); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_gen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "api/yajl_gen.h" 18 | #include "yajl_buf.h" 19 | #include "yajl_encode.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef enum { 28 | yajl_gen_start, 29 | yajl_gen_map_start, 30 | yajl_gen_map_key, 31 | yajl_gen_map_val, 32 | yajl_gen_array_start, 33 | yajl_gen_in_array, 34 | yajl_gen_complete, 35 | yajl_gen_error 36 | } yajl_gen_state; 37 | 38 | struct yajl_gen_t 39 | { 40 | unsigned int flags; 41 | unsigned int depth; 42 | const char * indentString; 43 | yajl_gen_state state[YAJL_MAX_DEPTH]; 44 | yajl_print_t print; 45 | void * ctx; /* yajl_buf */ 46 | /* memory allocation routines */ 47 | yajl_alloc_funcs alloc; 48 | }; 49 | 50 | int 51 | yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...) 52 | { 53 | int rv = 1; 54 | va_list ap; 55 | va_start(ap, opt); 56 | 57 | switch(opt) { 58 | case yajl_gen_beautify: 59 | case yajl_gen_validate_utf8: 60 | case yajl_gen_escape_solidus: 61 | if (va_arg(ap, int)) g->flags |= opt; 62 | else g->flags &= ~opt; 63 | break; 64 | case yajl_gen_indent_string: { 65 | const char *indent = va_arg(ap, const char *); 66 | g->indentString = indent; 67 | for (; *indent; indent++) { 68 | if (*indent != '\n' 69 | && *indent != '\v' 70 | && *indent != '\f' 71 | && *indent != '\t' 72 | && *indent != '\r' 73 | && *indent != ' ') 74 | { 75 | g->indentString = NULL; 76 | rv = 0; 77 | } 78 | } 79 | break; 80 | } 81 | case yajl_gen_print_callback: 82 | yajl_buf_free(g->ctx); 83 | g->print = va_arg(ap, const yajl_print_t); 84 | g->ctx = va_arg(ap, void *); 85 | break; 86 | default: 87 | rv = 0; 88 | } 89 | 90 | va_end(ap); 91 | 92 | return rv; 93 | } 94 | 95 | 96 | 97 | yajl_gen 98 | yajl_gen_alloc(const yajl_alloc_funcs * afs) 99 | { 100 | yajl_gen g = NULL; 101 | yajl_alloc_funcs afsBuffer; 102 | 103 | /* first order of business is to set up memory allocation routines */ 104 | if (afs != NULL) { 105 | if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) 106 | { 107 | return NULL; 108 | } 109 | } else { 110 | yajl_set_default_alloc_funcs(&afsBuffer); 111 | afs = &afsBuffer; 112 | } 113 | 114 | g = (yajl_gen) YA_MALLOC(afs, sizeof(struct yajl_gen_t)); 115 | if (!g) return NULL; 116 | 117 | memset((void *) g, 0, sizeof(struct yajl_gen_t)); 118 | /* copy in pointers to allocation routines */ 119 | memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); 120 | 121 | g->print = (yajl_print_t)&yajl_buf_append; 122 | g->ctx = yajl_buf_alloc(&(g->alloc)); 123 | g->indentString = " "; 124 | 125 | return g; 126 | } 127 | 128 | void 129 | yajl_gen_reset(yajl_gen g, const char * sep) 130 | { 131 | g->depth = 0; 132 | memset((void *) &(g->state), 0, sizeof(g->state)); 133 | if (sep != NULL) g->print(g->ctx, sep, strlen(sep)); 134 | } 135 | 136 | void 137 | yajl_gen_free(yajl_gen g) 138 | { 139 | if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_free((yajl_buf)g->ctx); 140 | YA_FREE(&(g->alloc), g); 141 | } 142 | 143 | #define INSERT_SEP \ 144 | if (g->state[g->depth] == yajl_gen_map_key || \ 145 | g->state[g->depth] == yajl_gen_in_array) { \ 146 | g->print(g->ctx, ",", 1); \ 147 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); \ 148 | } else if (g->state[g->depth] == yajl_gen_map_val) { \ 149 | g->print(g->ctx, ":", 1); \ 150 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, " ", 1); \ 151 | } 152 | 153 | #define INSERT_WHITESPACE \ 154 | if ((g->flags & yajl_gen_beautify)) { \ 155 | if (g->state[g->depth] != yajl_gen_map_val) { \ 156 | unsigned int _i; \ 157 | for (_i=0;_idepth;_i++) \ 158 | g->print(g->ctx, \ 159 | g->indentString, \ 160 | (unsigned int)strlen(g->indentString)); \ 161 | } \ 162 | } 163 | 164 | #define ENSURE_NOT_KEY \ 165 | if (g->state[g->depth] == yajl_gen_map_key || \ 166 | g->state[g->depth] == yajl_gen_map_start) { \ 167 | return yajl_gen_keys_must_be_strings; \ 168 | } \ 169 | 170 | /* check that we're not complete, or in error state. in a valid state 171 | * to be generating */ 172 | #define ENSURE_VALID_STATE \ 173 | if (g->state[g->depth] == yajl_gen_error) { \ 174 | return yajl_gen_in_error_state;\ 175 | } else if (g->state[g->depth] == yajl_gen_complete) { \ 176 | return yajl_gen_generation_complete; \ 177 | } 178 | 179 | #define INCREMENT_DEPTH \ 180 | if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded; 181 | 182 | #define DECREMENT_DEPTH \ 183 | if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_gen_generation_complete; 184 | 185 | #define APPENDED_ATOM \ 186 | switch (g->state[g->depth]) { \ 187 | case yajl_gen_start: \ 188 | g->state[g->depth] = yajl_gen_complete; \ 189 | break; \ 190 | case yajl_gen_map_start: \ 191 | case yajl_gen_map_key: \ 192 | g->state[g->depth] = yajl_gen_map_val; \ 193 | break; \ 194 | case yajl_gen_array_start: \ 195 | g->state[g->depth] = yajl_gen_in_array; \ 196 | break; \ 197 | case yajl_gen_map_val: \ 198 | g->state[g->depth] = yajl_gen_map_key; \ 199 | break; \ 200 | default: \ 201 | break; \ 202 | } \ 203 | 204 | #define FINAL_NEWLINE \ 205 | if ((g->flags & yajl_gen_beautify) && g->state[g->depth] == yajl_gen_complete) \ 206 | g->print(g->ctx, "\n", 1); 207 | 208 | yajl_gen_status 209 | yajl_gen_integer(yajl_gen g, long long int number) 210 | { 211 | char i[32]; 212 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 213 | sprintf(i, "%lld", number); 214 | g->print(g->ctx, i, (unsigned int)strlen(i)); 215 | APPENDED_ATOM; 216 | FINAL_NEWLINE; 217 | return yajl_gen_status_ok; 218 | } 219 | 220 | #if defined(_WIN32) || defined(WIN32) 221 | #include 222 | #define isnan _isnan 223 | #define isinf !_finite 224 | #endif 225 | 226 | yajl_gen_status 227 | yajl_gen_double(yajl_gen g, double number) 228 | { 229 | char i[32]; 230 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; 231 | if (isnan(number) || isinf(number)) return yajl_gen_invalid_number; 232 | INSERT_SEP; INSERT_WHITESPACE; 233 | sprintf(i, "%.20g", number); 234 | if (strspn(i, "0123456789-") == strlen(i)) { 235 | strcat(i, ".0"); 236 | } 237 | g->print(g->ctx, i, (unsigned int)strlen(i)); 238 | APPENDED_ATOM; 239 | FINAL_NEWLINE; 240 | return yajl_gen_status_ok; 241 | } 242 | 243 | yajl_gen_status 244 | yajl_gen_number(yajl_gen g, const char * s, size_t l) 245 | { 246 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 247 | g->print(g->ctx, s, l); 248 | APPENDED_ATOM; 249 | FINAL_NEWLINE; 250 | return yajl_gen_status_ok; 251 | } 252 | 253 | yajl_gen_status 254 | yajl_gen_string(yajl_gen g, const unsigned char * str, 255 | size_t len) 256 | { 257 | // if validation is enabled, check that the string is valid utf8 258 | // XXX: This checking could be done a little faster, in the same pass as 259 | // the string encoding 260 | if (g->flags & yajl_gen_validate_utf8) { 261 | if (!yajl_string_validate_utf8(str, len)) { 262 | return yajl_gen_invalid_string; 263 | } 264 | } 265 | ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE; 266 | g->print(g->ctx, "\"", 1); 267 | yajl_string_encode(g->print, g->ctx, str, len, g->flags & yajl_gen_escape_solidus); 268 | g->print(g->ctx, "\"", 1); 269 | APPENDED_ATOM; 270 | FINAL_NEWLINE; 271 | return yajl_gen_status_ok; 272 | } 273 | 274 | yajl_gen_status 275 | yajl_gen_null(yajl_gen g) 276 | { 277 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 278 | g->print(g->ctx, "null", strlen("null")); 279 | APPENDED_ATOM; 280 | FINAL_NEWLINE; 281 | return yajl_gen_status_ok; 282 | } 283 | 284 | yajl_gen_status 285 | yajl_gen_bool(yajl_gen g, int boolean) 286 | { 287 | const char * val = boolean ? "true" : "false"; 288 | 289 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 290 | g->print(g->ctx, val, (unsigned int)strlen(val)); 291 | APPENDED_ATOM; 292 | FINAL_NEWLINE; 293 | return yajl_gen_status_ok; 294 | } 295 | 296 | yajl_gen_status 297 | yajl_gen_map_open(yajl_gen g) 298 | { 299 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 300 | INCREMENT_DEPTH; 301 | 302 | g->state[g->depth] = yajl_gen_map_start; 303 | g->print(g->ctx, "{", 1); 304 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); 305 | FINAL_NEWLINE; 306 | return yajl_gen_status_ok; 307 | } 308 | 309 | yajl_gen_status 310 | yajl_gen_map_close(yajl_gen g) 311 | { 312 | ENSURE_VALID_STATE; 313 | DECREMENT_DEPTH; 314 | 315 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); 316 | APPENDED_ATOM; 317 | INSERT_WHITESPACE; 318 | g->print(g->ctx, "}", 1); 319 | FINAL_NEWLINE; 320 | return yajl_gen_status_ok; 321 | } 322 | 323 | yajl_gen_status 324 | yajl_gen_array_open(yajl_gen g) 325 | { 326 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 327 | INCREMENT_DEPTH; 328 | g->state[g->depth] = yajl_gen_array_start; 329 | g->print(g->ctx, "[", 1); 330 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); 331 | FINAL_NEWLINE; 332 | return yajl_gen_status_ok; 333 | } 334 | 335 | yajl_gen_status 336 | yajl_gen_array_close(yajl_gen g) 337 | { 338 | ENSURE_VALID_STATE; 339 | DECREMENT_DEPTH; 340 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); 341 | APPENDED_ATOM; 342 | INSERT_WHITESPACE; 343 | g->print(g->ctx, "]", 1); 344 | FINAL_NEWLINE; 345 | return yajl_gen_status_ok; 346 | } 347 | 348 | yajl_gen_status 349 | yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf, 350 | size_t * len) 351 | { 352 | if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf; 353 | *buf = yajl_buf_data((yajl_buf)g->ctx); 354 | *len = yajl_buf_len((yajl_buf)g->ctx); 355 | return yajl_gen_status_ok; 356 | } 357 | 358 | void 359 | yajl_gen_clear(yajl_gen g) 360 | { 361 | if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_clear((yajl_buf)g->ctx); 362 | } 363 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_lex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __YAJL_LEX_H__ 18 | #define __YAJL_LEX_H__ 19 | 20 | #include "api/yajl_common.h" 21 | 22 | typedef enum { 23 | yajl_tok_bool, 24 | yajl_tok_colon, 25 | yajl_tok_comma, 26 | yajl_tok_eof, 27 | yajl_tok_error, 28 | yajl_tok_left_brace, 29 | yajl_tok_left_bracket, 30 | yajl_tok_null, 31 | yajl_tok_right_brace, 32 | yajl_tok_right_bracket, 33 | 34 | /* we differentiate between integers and doubles to allow the 35 | * parser to interpret the number without re-scanning */ 36 | yajl_tok_integer, 37 | yajl_tok_double, 38 | 39 | /* we differentiate between strings which require further processing, 40 | * and strings that do not */ 41 | yajl_tok_string, 42 | yajl_tok_string_with_escapes, 43 | 44 | /* comment tokens are not currently returned to the parser, ever */ 45 | yajl_tok_comment 46 | } yajl_tok; 47 | 48 | typedef struct yajl_lexer_t * yajl_lexer; 49 | 50 | yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc, 51 | unsigned int allowComments, 52 | unsigned int validateUTF8); 53 | 54 | void yajl_lex_free(yajl_lexer lexer); 55 | 56 | /** 57 | * run/continue a lex. "offset" is an input/output parameter. 58 | * It should be initialized to zero for a 59 | * new chunk of target text, and upon subsequent calls with the same 60 | * target text should passed with the value of the previous invocation. 61 | * 62 | * the client may be interested in the value of offset when an error is 63 | * returned from the lexer. This allows the client to render useful 64 | * error messages. 65 | * 66 | * When you pass the next chunk of data, context should be reinitialized 67 | * to zero. 68 | * 69 | * Finally, the output buffer is usually just a pointer into the jsonText, 70 | * however in cases where the entity being lexed spans multiple chunks, 71 | * the lexer will buffer the entity and the data returned will be 72 | * a pointer into that buffer. 73 | * 74 | * This behavior is abstracted from client code except for the performance 75 | * implications which require that the client choose a reasonable chunk 76 | * size to get adequate performance. 77 | */ 78 | yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, 79 | size_t jsonTextLen, size_t * offset, 80 | const unsigned char ** outBuf, size_t * outLen); 81 | 82 | /** have a peek at the next token, but don't move the lexer forward */ 83 | yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, 84 | size_t jsonTextLen, size_t offset); 85 | 86 | 87 | typedef enum { 88 | yajl_lex_e_ok = 0, 89 | yajl_lex_string_invalid_utf8, 90 | yajl_lex_string_invalid_escaped_char, 91 | yajl_lex_string_invalid_json_char, 92 | yajl_lex_string_invalid_hex_char, 93 | yajl_lex_invalid_char, 94 | yajl_lex_invalid_string, 95 | yajl_lex_missing_integer_after_decimal, 96 | yajl_lex_missing_integer_after_exponent, 97 | yajl_lex_missing_integer_after_minus, 98 | yajl_lex_unallowed_comment 99 | } yajl_lex_error; 100 | 101 | const char * yajl_lex_error_to_string(yajl_lex_error error); 102 | 103 | /** allows access to more specific information about the lexical 104 | * error when yajl_lex_lex returns yajl_tok_error. */ 105 | yajl_lex_error yajl_lex_get_error(yajl_lexer lexer); 106 | 107 | /** get the current offset into the most recently lexed json string. */ 108 | size_t yajl_lex_current_offset(yajl_lexer lexer); 109 | 110 | /** get the number of lines lexed by this lexer instance */ 111 | size_t yajl_lex_current_line(yajl_lexer lexer); 112 | 113 | /** get the number of chars lexed by this lexer instance since the last 114 | * \n or \r */ 115 | size_t yajl_lex_current_char(yajl_lexer lexer); 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "api/yajl_parse.h" 18 | #include "yajl_lex.h" 19 | #include "yajl_parser.h" 20 | #include "yajl_encode.h" 21 | #include "yajl_bytestack.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10)) 33 | 34 | /* same semantics as strtol */ 35 | long long 36 | yajl_parse_integer(const unsigned char *number, size_t length) 37 | { 38 | long long ret = 0; 39 | long sign = 1; 40 | const unsigned char *pos = number; 41 | if (*pos == '-') { pos++; sign = -1; } 42 | if (*pos == '+') { pos++; } 43 | 44 | while (pos < number + length) { 45 | if ( ret > MAX_VALUE_TO_MULTIPLY ) { 46 | errno = ERANGE; 47 | return sign == 1 ? LLONG_MAX : LLONG_MIN; 48 | } 49 | ret *= 10; 50 | if (LLONG_MAX - ret < (*pos - '0')) { 51 | errno = ERANGE; 52 | return sign == 1 ? LLONG_MAX : LLONG_MIN; 53 | } 54 | if (*pos < '0' || *pos > '9') { 55 | errno = ERANGE; 56 | return sign == 1 ? LLONG_MAX : LLONG_MIN; 57 | } 58 | ret += (*pos++ - '0'); 59 | } 60 | 61 | return sign * ret; 62 | } 63 | 64 | unsigned char * 65 | yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, 66 | size_t jsonTextLen, int verbose) 67 | { 68 | size_t offset = hand->bytesConsumed; 69 | unsigned char * str; 70 | const char * errorType = NULL; 71 | const char * errorText = NULL; 72 | char text[72]; 73 | const char * arrow = " (right here) ------^\n"; 74 | 75 | if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) { 76 | errorType = "parse"; 77 | errorText = hand->parseError; 78 | } else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) { 79 | errorType = "lexical"; 80 | errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer)); 81 | } else { 82 | errorType = "unknown"; 83 | } 84 | 85 | { 86 | size_t memneeded = 0; 87 | memneeded += strlen(errorType); 88 | memneeded += strlen(" error"); 89 | if (errorText != NULL) { 90 | memneeded += strlen(": "); 91 | memneeded += strlen(errorText); 92 | } 93 | str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2); 94 | if (!str) return NULL; 95 | str[0] = 0; 96 | strcat((char *) str, errorType); 97 | strcat((char *) str, " error"); 98 | if (errorText != NULL) { 99 | strcat((char *) str, ": "); 100 | strcat((char *) str, errorText); 101 | } 102 | strcat((char *) str, "\n"); 103 | } 104 | 105 | /* now we append as many spaces as needed to make sure the error 106 | * falls at char 41, if verbose was specified */ 107 | if (verbose) { 108 | size_t start, end, i; 109 | size_t spacesNeeded; 110 | 111 | spacesNeeded = (offset < 30 ? 40 - offset : 10); 112 | start = (offset >= 30 ? offset - 30 : 0); 113 | end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30); 114 | 115 | for (i=0;ialloc), (unsigned int)(strlen((char *) str) + 133 | strlen((char *) text) + 134 | strlen(arrow) + 1)); 135 | if (newStr) { 136 | newStr[0] = 0; 137 | strcat((char *) newStr, (char *) str); 138 | strcat((char *) newStr, text); 139 | strcat((char *) newStr, arrow); 140 | } 141 | YA_FREE(&(hand->alloc), str); 142 | str = (unsigned char *) newStr; 143 | } 144 | } 145 | return str; 146 | } 147 | 148 | /* check for client cancelation */ 149 | #define _CC_CHK(x) \ 150 | if (!(x)) { \ 151 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); \ 152 | hand->parseError = \ 153 | "client cancelled parse via callback return value"; \ 154 | return yajl_status_client_canceled; \ 155 | } 156 | 157 | 158 | yajl_status 159 | yajl_do_finish(yajl_handle hand) 160 | { 161 | yajl_status stat; 162 | stat = yajl_do_parse(hand,(const unsigned char *) " ",1); 163 | 164 | if (stat != yajl_status_ok) return stat; 165 | 166 | switch(yajl_bs_current(hand->stateStack)) 167 | { 168 | case yajl_state_parse_error: 169 | case yajl_state_lexical_error: 170 | return yajl_status_error; 171 | case yajl_state_got_value: 172 | case yajl_state_parse_complete: 173 | return yajl_status_ok; 174 | default: 175 | if (!(hand->flags & yajl_allow_partial_values)) 176 | { 177 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 178 | hand->parseError = "premature EOF"; 179 | return yajl_status_error; 180 | } 181 | return yajl_status_ok; 182 | } 183 | } 184 | 185 | yajl_status 186 | yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, 187 | size_t jsonTextLen) 188 | { 189 | yajl_tok tok; 190 | const unsigned char * buf; 191 | size_t bufLen; 192 | size_t * offset = &(hand->bytesConsumed); 193 | 194 | *offset = 0; 195 | 196 | around_again: 197 | switch (yajl_bs_current(hand->stateStack)) { 198 | case yajl_state_parse_complete: 199 | if (hand->flags & yajl_allow_multiple_values) { 200 | yajl_bs_set(hand->stateStack, yajl_state_got_value); 201 | goto around_again; 202 | } 203 | if (!(hand->flags & yajl_allow_trailing_garbage)) { 204 | if (*offset != jsonTextLen) { 205 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 206 | offset, &buf, &bufLen); 207 | if (tok != yajl_tok_eof) { 208 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 209 | hand->parseError = "trailing garbage"; 210 | } 211 | goto around_again; 212 | } 213 | } 214 | return yajl_status_ok; 215 | case yajl_state_lexical_error: 216 | case yajl_state_parse_error: 217 | return yajl_status_error; 218 | case yajl_state_start: 219 | case yajl_state_got_value: 220 | case yajl_state_map_need_val: 221 | case yajl_state_array_need_val: 222 | case yajl_state_array_start: { 223 | /* for arrays and maps, we advance the state for this 224 | * depth, then push the state of the next depth. 225 | * If an error occurs during the parsing of the nesting 226 | * enitity, the state at this level will not matter. 227 | * a state that needs pushing will be anything other 228 | * than state_start */ 229 | 230 | yajl_state stateToPush = yajl_state_start; 231 | 232 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 233 | offset, &buf, &bufLen); 234 | 235 | switch (tok) { 236 | case yajl_tok_eof: 237 | return yajl_status_ok; 238 | case yajl_tok_error: 239 | yajl_bs_set(hand->stateStack, yajl_state_lexical_error); 240 | goto around_again; 241 | case yajl_tok_string: 242 | if (hand->callbacks && hand->callbacks->yajl_string) { 243 | _CC_CHK(hand->callbacks->yajl_string(hand->ctx, 244 | buf, bufLen)); 245 | } 246 | break; 247 | case yajl_tok_string_with_escapes: 248 | if (hand->callbacks && hand->callbacks->yajl_string) { 249 | yajl_buf_clear(hand->decodeBuf); 250 | yajl_string_decode(hand->decodeBuf, buf, bufLen); 251 | _CC_CHK(hand->callbacks->yajl_string( 252 | hand->ctx, yajl_buf_data(hand->decodeBuf), 253 | yajl_buf_len(hand->decodeBuf))); 254 | } 255 | break; 256 | case yajl_tok_bool: 257 | if (hand->callbacks && hand->callbacks->yajl_boolean) { 258 | _CC_CHK(hand->callbacks->yajl_boolean(hand->ctx, 259 | *buf == 't')); 260 | } 261 | break; 262 | case yajl_tok_null: 263 | if (hand->callbacks && hand->callbacks->yajl_null) { 264 | _CC_CHK(hand->callbacks->yajl_null(hand->ctx)); 265 | } 266 | break; 267 | case yajl_tok_left_bracket: 268 | if (hand->callbacks && hand->callbacks->yajl_start_map) { 269 | _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx)); 270 | } 271 | stateToPush = yajl_state_map_start; 272 | break; 273 | case yajl_tok_left_brace: 274 | if (hand->callbacks && hand->callbacks->yajl_start_array) { 275 | _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx)); 276 | } 277 | stateToPush = yajl_state_array_start; 278 | break; 279 | case yajl_tok_integer: 280 | if (hand->callbacks) { 281 | if (hand->callbacks->yajl_number) { 282 | _CC_CHK(hand->callbacks->yajl_number( 283 | hand->ctx,(const char *) buf, bufLen)); 284 | } else if (hand->callbacks->yajl_integer) { 285 | long long int i = 0; 286 | errno = 0; 287 | i = yajl_parse_integer(buf, bufLen); 288 | if ((i == LLONG_MIN || i == LLONG_MAX) && 289 | errno == ERANGE) 290 | { 291 | yajl_bs_set(hand->stateStack, 292 | yajl_state_parse_error); 293 | hand->parseError = "integer overflow" ; 294 | /* try to restore error offset */ 295 | if (*offset >= bufLen) *offset -= bufLen; 296 | else *offset = 0; 297 | goto around_again; 298 | } 299 | _CC_CHK(hand->callbacks->yajl_integer(hand->ctx, 300 | i)); 301 | } 302 | } 303 | break; 304 | case yajl_tok_double: 305 | if (hand->callbacks) { 306 | if (hand->callbacks->yajl_number) { 307 | _CC_CHK(hand->callbacks->yajl_number( 308 | hand->ctx, (const char *) buf, bufLen)); 309 | } else if (hand->callbacks->yajl_double) { 310 | double d = 0.0; 311 | yajl_buf_clear(hand->decodeBuf); 312 | yajl_buf_append(hand->decodeBuf, buf, bufLen); 313 | buf = yajl_buf_data(hand->decodeBuf); 314 | errno = 0; 315 | d = strtod((char *) buf, NULL); 316 | if ((d == HUGE_VAL || d == -HUGE_VAL) && 317 | errno == ERANGE) 318 | { 319 | yajl_bs_set(hand->stateStack, 320 | yajl_state_parse_error); 321 | hand->parseError = "numeric (floating point) " 322 | "overflow"; 323 | /* try to restore error offset */ 324 | if (*offset >= bufLen) *offset -= bufLen; 325 | else *offset = 0; 326 | goto around_again; 327 | } 328 | _CC_CHK(hand->callbacks->yajl_double(hand->ctx, 329 | d)); 330 | } 331 | } 332 | break; 333 | case yajl_tok_right_brace: { 334 | if (yajl_bs_current(hand->stateStack) == 335 | yajl_state_array_start) 336 | { 337 | if (hand->callbacks && 338 | hand->callbacks->yajl_end_array) 339 | { 340 | _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); 341 | } 342 | yajl_bs_pop(hand->stateStack); 343 | goto around_again; 344 | } 345 | /* intentional fall-through */ 346 | } 347 | case yajl_tok_colon: 348 | case yajl_tok_comma: 349 | case yajl_tok_right_bracket: 350 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 351 | hand->parseError = 352 | "unallowed token at this point in JSON text"; 353 | goto around_again; 354 | default: 355 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 356 | hand->parseError = "invalid token, internal error"; 357 | goto around_again; 358 | } 359 | /* got a value. transition depends on the state we're in. */ 360 | { 361 | yajl_state s = yajl_bs_current(hand->stateStack); 362 | if (s == yajl_state_start || s == yajl_state_got_value) { 363 | yajl_bs_set(hand->stateStack, yajl_state_parse_complete); 364 | } else if (s == yajl_state_map_need_val) { 365 | yajl_bs_set(hand->stateStack, yajl_state_map_got_val); 366 | } else { 367 | yajl_bs_set(hand->stateStack, yajl_state_array_got_val); 368 | } 369 | } 370 | if (stateToPush != yajl_state_start) { 371 | yajl_bs_push(hand->stateStack, stateToPush); 372 | } 373 | 374 | goto around_again; 375 | } 376 | case yajl_state_map_start: 377 | case yajl_state_map_need_key: { 378 | /* only difference between these two states is that in 379 | * start '}' is valid, whereas in need_key, we've parsed 380 | * a comma, and a string key _must_ follow */ 381 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 382 | offset, &buf, &bufLen); 383 | switch (tok) { 384 | case yajl_tok_eof: 385 | return yajl_status_ok; 386 | case yajl_tok_error: 387 | yajl_bs_set(hand->stateStack, yajl_state_lexical_error); 388 | goto around_again; 389 | case yajl_tok_string_with_escapes: 390 | if (hand->callbacks && hand->callbacks->yajl_map_key) { 391 | yajl_buf_clear(hand->decodeBuf); 392 | yajl_string_decode(hand->decodeBuf, buf, bufLen); 393 | buf = yajl_buf_data(hand->decodeBuf); 394 | bufLen = yajl_buf_len(hand->decodeBuf); 395 | } 396 | /* intentional fall-through */ 397 | case yajl_tok_string: 398 | if (hand->callbacks && hand->callbacks->yajl_map_key) { 399 | _CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf, 400 | bufLen)); 401 | } 402 | yajl_bs_set(hand->stateStack, yajl_state_map_sep); 403 | goto around_again; 404 | case yajl_tok_right_bracket: 405 | if (yajl_bs_current(hand->stateStack) == 406 | yajl_state_map_start) 407 | { 408 | if (hand->callbacks && hand->callbacks->yajl_end_map) { 409 | _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); 410 | } 411 | yajl_bs_pop(hand->stateStack); 412 | goto around_again; 413 | } 414 | default: 415 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 416 | hand->parseError = 417 | "invalid object key (must be a string)"; 418 | goto around_again; 419 | } 420 | } 421 | case yajl_state_map_sep: { 422 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 423 | offset, &buf, &bufLen); 424 | switch (tok) { 425 | case yajl_tok_colon: 426 | yajl_bs_set(hand->stateStack, yajl_state_map_need_val); 427 | goto around_again; 428 | case yajl_tok_eof: 429 | return yajl_status_ok; 430 | case yajl_tok_error: 431 | yajl_bs_set(hand->stateStack, yajl_state_lexical_error); 432 | goto around_again; 433 | default: 434 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 435 | hand->parseError = "object key and value must " 436 | "be separated by a colon (':')"; 437 | goto around_again; 438 | } 439 | } 440 | case yajl_state_map_got_val: { 441 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 442 | offset, &buf, &bufLen); 443 | switch (tok) { 444 | case yajl_tok_right_bracket: 445 | if (hand->callbacks && hand->callbacks->yajl_end_map) { 446 | _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); 447 | } 448 | yajl_bs_pop(hand->stateStack); 449 | goto around_again; 450 | case yajl_tok_comma: 451 | yajl_bs_set(hand->stateStack, yajl_state_map_need_key); 452 | goto around_again; 453 | case yajl_tok_eof: 454 | return yajl_status_ok; 455 | case yajl_tok_error: 456 | yajl_bs_set(hand->stateStack, yajl_state_lexical_error); 457 | goto around_again; 458 | default: 459 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 460 | hand->parseError = "after key and value, inside map, " 461 | "I expect ',' or '}'"; 462 | /* try to restore error offset */ 463 | if (*offset >= bufLen) *offset -= bufLen; 464 | else *offset = 0; 465 | goto around_again; 466 | } 467 | } 468 | case yajl_state_array_got_val: { 469 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 470 | offset, &buf, &bufLen); 471 | switch (tok) { 472 | case yajl_tok_right_brace: 473 | if (hand->callbacks && hand->callbacks->yajl_end_array) { 474 | _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); 475 | } 476 | yajl_bs_pop(hand->stateStack); 477 | goto around_again; 478 | case yajl_tok_comma: 479 | yajl_bs_set(hand->stateStack, yajl_state_array_need_val); 480 | goto around_again; 481 | case yajl_tok_eof: 482 | return yajl_status_ok; 483 | case yajl_tok_error: 484 | yajl_bs_set(hand->stateStack, yajl_state_lexical_error); 485 | goto around_again; 486 | default: 487 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 488 | hand->parseError = 489 | "after array element, I expect ',' or ']'"; 490 | goto around_again; 491 | } 492 | } 493 | } 494 | 495 | abort(); 496 | return yajl_status_error; 497 | } 498 | 499 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __YAJL_PARSER_H__ 18 | #define __YAJL_PARSER_H__ 19 | 20 | #include "api/yajl_parse.h" 21 | #include "yajl_bytestack.h" 22 | #include "yajl_buf.h" 23 | #include "yajl_lex.h" 24 | 25 | 26 | typedef enum { 27 | yajl_state_start = 0, 28 | yajl_state_parse_complete, 29 | yajl_state_parse_error, 30 | yajl_state_lexical_error, 31 | yajl_state_map_start, 32 | yajl_state_map_sep, 33 | yajl_state_map_need_val, 34 | yajl_state_map_got_val, 35 | yajl_state_map_need_key, 36 | yajl_state_array_start, 37 | yajl_state_array_got_val, 38 | yajl_state_array_need_val, 39 | yajl_state_got_value, 40 | } yajl_state; 41 | 42 | struct yajl_handle_t { 43 | const yajl_callbacks * callbacks; 44 | void * ctx; 45 | yajl_lexer lexer; 46 | const char * parseError; 47 | /* the number of bytes consumed from the last client buffer, 48 | * in the case of an error this will be an error offset, in the 49 | * case of an error this can be used as the error offset */ 50 | size_t bytesConsumed; 51 | /* temporary storage for decoded strings */ 52 | yajl_buf decodeBuf; 53 | /* a stack of states. access with yajl_state_XXX routines */ 54 | yajl_bytestack stateStack; 55 | /* memory allocation routines */ 56 | yajl_alloc_funcs alloc; 57 | /* bitfield */ 58 | unsigned int flags; 59 | }; 60 | 61 | yajl_status 62 | yajl_do_parse(yajl_handle handle, const unsigned char * jsonText, 63 | size_t jsonTextLen); 64 | 65 | yajl_status 66 | yajl_do_finish(yajl_handle handle); 67 | 68 | unsigned char * 69 | yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, 70 | size_t jsonTextLen, int verbose); 71 | 72 | /* A little built in integer parsing routine with the same semantics as strtol 73 | * that's unaffected by LOCALE. */ 74 | long long 75 | yajl_parse_integer(const unsigned char *number, size_t length); 76 | 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011 Florian Forster 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "api/yajl_tree.h" 24 | #include "api/yajl_parse.h" 25 | 26 | #include "yajl_parser.h" 27 | 28 | #if defined(_WIN32) || defined(WIN32) 29 | #define snprintf sprintf_s 30 | #endif 31 | 32 | #define STATUS_CONTINUE 1 33 | #define STATUS_ABORT 0 34 | 35 | struct stack_elem_s; 36 | typedef struct stack_elem_s stack_elem_t; 37 | struct stack_elem_s 38 | { 39 | char * key; 40 | yajl_val value; 41 | stack_elem_t *next; 42 | }; 43 | 44 | struct context_s 45 | { 46 | stack_elem_t *stack; 47 | yajl_val root; 48 | char *errbuf; 49 | size_t errbuf_size; 50 | }; 51 | typedef struct context_s context_t; 52 | 53 | #define RETURN_ERROR(ctx,retval,...) { \ 54 | if ((ctx)->errbuf != NULL) \ 55 | snprintf ((ctx)->errbuf, (ctx)->errbuf_size, __VA_ARGS__); \ 56 | return (retval); \ 57 | } 58 | 59 | static yajl_val value_alloc (yajl_type type) 60 | { 61 | yajl_val v; 62 | 63 | v = malloc (sizeof (*v)); 64 | if (v == NULL) return (NULL); 65 | memset (v, 0, sizeof (*v)); 66 | v->type = type; 67 | 68 | return (v); 69 | } 70 | 71 | static void yajl_object_free (yajl_val v) 72 | { 73 | size_t i; 74 | 75 | if (!YAJL_IS_OBJECT(v)) return; 76 | 77 | for (i = 0; i < v->u.object.len; i++) 78 | { 79 | free((char *) v->u.object.keys[i]); 80 | v->u.object.keys[i] = NULL; 81 | yajl_tree_free (v->u.object.values[i]); 82 | v->u.object.values[i] = NULL; 83 | } 84 | 85 | free((void*) v->u.object.keys); 86 | free(v->u.object.values); 87 | free(v); 88 | } 89 | 90 | static void yajl_array_free (yajl_val v) 91 | { 92 | size_t i; 93 | 94 | if (!YAJL_IS_ARRAY(v)) return; 95 | 96 | for (i = 0; i < v->u.array.len; i++) 97 | { 98 | yajl_tree_free (v->u.array.values[i]); 99 | v->u.array.values[i] = NULL; 100 | } 101 | 102 | free(v->u.array.values); 103 | free(v); 104 | } 105 | 106 | /* 107 | * Parsing nested objects and arrays is implemented using a stack. When a new 108 | * object or array starts (a curly or a square opening bracket is read), an 109 | * appropriate value is pushed on the stack. When the end of the object is 110 | * reached (an appropriate closing bracket has been read), the value is popped 111 | * off the stack and added to the enclosing object using "context_add_value". 112 | */ 113 | static int context_push(context_t *ctx, yajl_val v) 114 | { 115 | stack_elem_t *stack; 116 | 117 | stack = malloc (sizeof (*stack)); 118 | if (stack == NULL) 119 | RETURN_ERROR (ctx, ENOMEM, "Out of memory"); 120 | memset (stack, 0, sizeof (*stack)); 121 | 122 | assert ((ctx->stack == NULL) 123 | || YAJL_IS_OBJECT (v) 124 | || YAJL_IS_ARRAY (v)); 125 | 126 | stack->value = v; 127 | stack->next = ctx->stack; 128 | ctx->stack = stack; 129 | 130 | return (0); 131 | } 132 | 133 | static yajl_val context_pop(context_t *ctx) 134 | { 135 | stack_elem_t *stack; 136 | yajl_val v; 137 | 138 | if (ctx->stack == NULL) 139 | RETURN_ERROR (ctx, NULL, "context_pop: " 140 | "Bottom of stack reached prematurely"); 141 | 142 | stack = ctx->stack; 143 | ctx->stack = stack->next; 144 | 145 | v = stack->value; 146 | 147 | free (stack); 148 | 149 | return (v); 150 | } 151 | 152 | static int object_add_keyval(context_t *ctx, 153 | yajl_val obj, char *key, yajl_val value) 154 | { 155 | const char **tmpk; 156 | yajl_val *tmpv; 157 | 158 | /* We're checking for NULL in "context_add_value" or its callers. */ 159 | assert (ctx != NULL); 160 | assert (obj != NULL); 161 | assert (key != NULL); 162 | assert (value != NULL); 163 | 164 | /* We're assuring that "obj" is an object in "context_add_value". */ 165 | assert(YAJL_IS_OBJECT(obj)); 166 | 167 | tmpk = realloc((void *) obj->u.object.keys, sizeof(*(obj->u.object.keys)) * (obj->u.object.len + 1)); 168 | if (tmpk == NULL) 169 | RETURN_ERROR(ctx, ENOMEM, "Out of memory"); 170 | obj->u.object.keys = tmpk; 171 | 172 | tmpv = realloc(obj->u.object.values, sizeof (*obj->u.object.values) * (obj->u.object.len + 1)); 173 | if (tmpv == NULL) 174 | RETURN_ERROR(ctx, ENOMEM, "Out of memory"); 175 | obj->u.object.values = tmpv; 176 | 177 | obj->u.object.keys[obj->u.object.len] = key; 178 | obj->u.object.values[obj->u.object.len] = value; 179 | obj->u.object.len++; 180 | 181 | return (0); 182 | } 183 | 184 | static int array_add_value (context_t *ctx, 185 | yajl_val array, yajl_val value) 186 | { 187 | yajl_val *tmp; 188 | 189 | /* We're checking for NULL pointers in "context_add_value" or its 190 | * callers. */ 191 | assert (ctx != NULL); 192 | assert (array != NULL); 193 | assert (value != NULL); 194 | 195 | /* "context_add_value" will only call us with array values. */ 196 | assert(YAJL_IS_ARRAY(array)); 197 | 198 | tmp = realloc(array->u.array.values, 199 | sizeof(*(array->u.array.values)) * (array->u.array.len + 1)); 200 | if (tmp == NULL) 201 | RETURN_ERROR(ctx, ENOMEM, "Out of memory"); 202 | array->u.array.values = tmp; 203 | array->u.array.values[array->u.array.len] = value; 204 | array->u.array.len++; 205 | 206 | return 0; 207 | } 208 | 209 | /* 210 | * Add a value to the value on top of the stack or the "root" member in the 211 | * context if the end of the parsing process is reached. 212 | */ 213 | static int context_add_value (context_t *ctx, yajl_val v) 214 | { 215 | /* We're checking for NULL values in all the calling functions. */ 216 | assert (ctx != NULL); 217 | assert (v != NULL); 218 | 219 | /* 220 | * There are three valid states in which this function may be called: 221 | * - There is no value on the stack => This is the only value. This is the 222 | * last step done when parsing a document. We assign the value to the 223 | * "root" member and return. 224 | * - The value on the stack is an object. In this case store the key on the 225 | * stack or, if the key has already been read, add key and value to the 226 | * object. 227 | * - The value on the stack is an array. In this case simply add the value 228 | * and return. 229 | */ 230 | if (ctx->stack == NULL) 231 | { 232 | assert (ctx->root == NULL); 233 | ctx->root = v; 234 | return (0); 235 | } 236 | else if (YAJL_IS_OBJECT (ctx->stack->value)) 237 | { 238 | if (ctx->stack->key == NULL) 239 | { 240 | if (!YAJL_IS_STRING (v)) 241 | RETURN_ERROR (ctx, EINVAL, "context_add_value: " 242 | "Object key is not a string (%#04x)", 243 | v->type); 244 | 245 | ctx->stack->key = v->u.string; 246 | v->u.string = NULL; 247 | free(v); 248 | return (0); 249 | } 250 | else /* if (ctx->key != NULL) */ 251 | { 252 | char * key; 253 | 254 | key = ctx->stack->key; 255 | ctx->stack->key = NULL; 256 | return (object_add_keyval (ctx, ctx->stack->value, key, v)); 257 | } 258 | } 259 | else if (YAJL_IS_ARRAY (ctx->stack->value)) 260 | { 261 | return (array_add_value (ctx, ctx->stack->value, v)); 262 | } 263 | else 264 | { 265 | RETURN_ERROR (ctx, EINVAL, "context_add_value: Cannot add value to " 266 | "a value of type %#04x (not a composite type)", 267 | ctx->stack->value->type); 268 | } 269 | } 270 | 271 | static int handle_string (void *ctx, 272 | const unsigned char *string, size_t string_length) 273 | { 274 | yajl_val v; 275 | 276 | v = value_alloc (yajl_t_string); 277 | if (v == NULL) 278 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 279 | 280 | v->u.string = malloc (string_length + 1); 281 | if (v->u.string == NULL) 282 | { 283 | free (v); 284 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 285 | } 286 | memcpy(v->u.string, string, string_length); 287 | v->u.string[string_length] = 0; 288 | 289 | return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 290 | } 291 | 292 | static int handle_number (void *ctx, const char *string, size_t string_length) 293 | { 294 | yajl_val v; 295 | char *endptr; 296 | 297 | v = value_alloc(yajl_t_number); 298 | if (v == NULL) 299 | RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory"); 300 | 301 | v->u.number.r = malloc(string_length + 1); 302 | if (v->u.number.r == NULL) 303 | { 304 | free(v); 305 | RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory"); 306 | } 307 | memcpy(v->u.number.r, string, string_length); 308 | v->u.number.r[string_length] = 0; 309 | 310 | v->u.number.flags = 0; 311 | 312 | errno = 0; 313 | v->u.number.i = yajl_parse_integer((const unsigned char *) v->u.number.r, 314 | strlen(v->u.number.r)); 315 | if (errno == 0) 316 | v->u.number.flags |= YAJL_NUMBER_INT_VALID; 317 | 318 | endptr = NULL; 319 | errno = 0; 320 | v->u.number.d = strtod(v->u.number.r, &endptr); 321 | if ((errno == 0) && (endptr != NULL) && (*endptr == 0)) 322 | v->u.number.flags |= YAJL_NUMBER_DOUBLE_VALID; 323 | 324 | return ((context_add_value(ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 325 | } 326 | 327 | static int handle_start_map (void *ctx) 328 | { 329 | yajl_val v; 330 | 331 | v = value_alloc(yajl_t_object); 332 | if (v == NULL) 333 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 334 | 335 | v->u.object.keys = NULL; 336 | v->u.object.values = NULL; 337 | v->u.object.len = 0; 338 | 339 | return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 340 | } 341 | 342 | static int handle_end_map (void *ctx) 343 | { 344 | yajl_val v; 345 | 346 | v = context_pop (ctx); 347 | if (v == NULL) 348 | return (STATUS_ABORT); 349 | 350 | return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 351 | } 352 | 353 | static int handle_start_array (void *ctx) 354 | { 355 | yajl_val v; 356 | 357 | v = value_alloc(yajl_t_array); 358 | if (v == NULL) 359 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 360 | 361 | v->u.array.values = NULL; 362 | v->u.array.len = 0; 363 | 364 | return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 365 | } 366 | 367 | static int handle_end_array (void *ctx) 368 | { 369 | yajl_val v; 370 | 371 | v = context_pop (ctx); 372 | if (v == NULL) 373 | return (STATUS_ABORT); 374 | 375 | return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 376 | } 377 | 378 | static int handle_boolean (void *ctx, int boolean_value) 379 | { 380 | yajl_val v; 381 | 382 | v = value_alloc (boolean_value ? yajl_t_true : yajl_t_false); 383 | if (v == NULL) 384 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 385 | 386 | return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 387 | } 388 | 389 | static int handle_null (void *ctx) 390 | { 391 | yajl_val v; 392 | 393 | v = value_alloc (yajl_t_null); 394 | if (v == NULL) 395 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 396 | 397 | return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 398 | } 399 | 400 | /* 401 | * Public functions 402 | */ 403 | yajl_val yajl_tree_parse (const char *input, 404 | char *error_buffer, size_t error_buffer_size) 405 | { 406 | static const yajl_callbacks callbacks = 407 | { 408 | /* null = */ handle_null, 409 | /* boolean = */ handle_boolean, 410 | /* integer = */ NULL, 411 | /* double = */ NULL, 412 | /* number = */ handle_number, 413 | /* string = */ handle_string, 414 | /* start map = */ handle_start_map, 415 | /* map key = */ handle_string, 416 | /* end map = */ handle_end_map, 417 | /* start array = */ handle_start_array, 418 | /* end array = */ handle_end_array 419 | }; 420 | 421 | yajl_handle handle; 422 | yajl_status status; 423 | char * internal_err_str; 424 | context_t ctx = { NULL, NULL, NULL, 0 }; 425 | 426 | ctx.errbuf = error_buffer; 427 | ctx.errbuf_size = error_buffer_size; 428 | 429 | if (error_buffer != NULL) 430 | memset (error_buffer, 0, error_buffer_size); 431 | 432 | handle = yajl_alloc (&callbacks, NULL, &ctx); 433 | yajl_config(handle, yajl_allow_comments, 1); 434 | 435 | status = yajl_parse(handle, 436 | (unsigned char *) input, 437 | strlen (input)); 438 | status = yajl_complete_parse (handle); 439 | if (status != yajl_status_ok) { 440 | if (error_buffer != NULL && error_buffer_size > 0) { 441 | internal_err_str = (char *) yajl_get_error(handle, 1, 442 | (const unsigned char *) input, 443 | strlen(input)); 444 | snprintf(error_buffer, error_buffer_size, "%s", internal_err_str); 445 | YA_FREE(&(handle->alloc), internal_err_str); 446 | } 447 | yajl_free (handle); 448 | return NULL; 449 | } 450 | 451 | yajl_free (handle); 452 | return (ctx.root); 453 | } 454 | 455 | yajl_val yajl_tree_get(yajl_val n, const char ** path, yajl_type type) 456 | { 457 | if (!path) return NULL; 458 | while (n && *path) { 459 | size_t i; 460 | size_t len; 461 | 462 | if (n->type != yajl_t_object) return NULL; 463 | len = n->u.object.len; 464 | for (i = 0; i < len; i++) { 465 | if (!strcmp(*path, n->u.object.keys[i])) { 466 | n = n->u.object.values[i]; 467 | break; 468 | } 469 | } 470 | if (i == len) return NULL; 471 | path++; 472 | } 473 | if (n && type != yajl_t_any && type != n->type) n = NULL; 474 | return n; 475 | } 476 | 477 | void yajl_tree_free (yajl_val v) 478 | { 479 | if (v == NULL) return; 480 | 481 | if (YAJL_IS_STRING(v)) 482 | { 483 | free(v->u.string); 484 | free(v); 485 | } 486 | else if (YAJL_IS_NUMBER(v)) 487 | { 488 | free(v->u.number.r); 489 | free(v); 490 | } 491 | else if (YAJL_GET_OBJECT(v)) 492 | { 493 | yajl_object_free(v); 494 | } 495 | else if (YAJL_GET_ARRAY(v)) 496 | { 497 | yajl_array_free(v); 498 | } 499 | else /* if (yajl_t_true or yajl_t_false or yajl_t_null) */ 500 | { 501 | free(v); 502 | } 503 | } 504 | -------------------------------------------------------------------------------- /yajl-2.1.0/yajl_version.c: -------------------------------------------------------------------------------- 1 | #include "api/yajl_version.h" 2 | 3 | int yajl_version(void) 4 | { 5 | return YAJL_VERSION; 6 | } 7 | 8 | --------------------------------------------------------------------------------