github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/json-framework/SBJson4Parser.h (about) 1 /* 2 Copyright (c) 2010-2013, Stig Brautaset. 3 All rights reserved. 4 5 Redistribution and use in source and binary forms, with or without 6 modification, are permitted provided that the following conditions are 7 met: 8 9 Redistributions of source code must retain the above copyright 10 notice, this list of conditions and the following disclaimer. 11 12 Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions and the following disclaimer in the 14 documentation and/or other materials provided with the distribution. 15 16 Neither the name of the the author nor the names of its contributors 17 may be used to endorse or promote products derived from this software 18 without specific prior written permission. 19 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #import <Foundation/Foundation.h> 34 #import "SBJson4StreamParser.h" 35 36 /** 37 Block called when the parser has parsed an item. This could be once 38 for each root document parsed, or once for each unwrapped root array element. 39 40 @param item contains the parsed item. 41 @param stop set to YES if you want the parser to stop 42 */ 43 typedef void (^SBJson4ValueBlock)(id item, BOOL* stop); 44 45 /** 46 Block called if an error occurs. 47 @param error the error. 48 */ 49 typedef void (^SBJson4ErrorBlock)(NSError* error); 50 51 /** 52 Block used to process parsed tokens as they are encountered. You can use this 53 to transform strings containing dates into NSDate, for example. 54 @param item the parsed token 55 @param path the JSON Path of the token 56 */ 57 typedef id (^SBJson4ProcessBlock)(id item, NSString* path); 58 59 60 /** 61 Parse one or more chunks of JSON data. 62 63 Using this class directly you can reduce the apparent latency for each 64 download/parse cycle of documents over a slow connection. You can start 65 parsing *and return chunks of the parsed document* before the entire 66 document is downloaded. 67 68 Using this class is also useful to parse huge documents on disk 69 bit by bit so you don't have to keep them all in memory. 70 71 JSON is mapped to Objective-C types in the following way: 72 73 - null -> NSNull 74 - string -> NSString 75 - array -> NSMutableArray 76 - object -> NSMutableDictionary 77 - true -> NSNumber's -numberWithBool:YES 78 - false -> NSNumber's -numberWithBool:NO 79 - number -> NSNumber 80 81 Since Objective-C doesn't have a dedicated class for boolean values, 82 these turns into NSNumber instances. However, since these are 83 initialised with the -initWithBool: method they round-trip back to JSON 84 properly. In other words, they won't silently suddenly become 0 or 1; 85 they'll be represented as 'true' and 'false' again. 86 87 Integers are parsed into either a `long long` or `unsigned long long` 88 type if they fit, else a `double` is used. All real & exponential numbers 89 are represented using a `double`. Previous versions of this library used 90 an NSDecimalNumber in some cases, but this is no longer the case. 91 92 The default behaviour is that your passed-in block is only called once the 93 entire input is parsed. If you set supportManyDocuments to YES and your input 94 contains multiple (whitespace limited) JSON documents your block will be called 95 for each document: 96 97 SBJson4ValueBlock block = ^(id v, BOOL *stop) { 98 BOOL isArray = [v isKindOfClass:[NSArray class]]; 99 NSLog(@"Found: %@", isArray ? @"Array" : @"Object"); 100 }; 101 102 SBJson4ErrorBlock eh = ^(NSError* err) { 103 NSLog(@"OOPS: %@", err); 104 }; 105 106 id parser = [SBJson4Parser multiRootParserWithBlock:block 107 errorHandler:eh]; 108 109 // Note that this input contains multiple top-level JSON documents 110 id data = [@"[]{}" dataWithEncoding:NSUTF8StringEncoding]; 111 [parser parse:data]; 112 [parser parse:data]; 113 114 The above example will print: 115 116 - Found: Array 117 - Found: Object 118 - Found: Array 119 - Found: Object 120 121 Often you won't have control over the input you're parsing, so can't make use 122 of this feature. But, all is not lost: if you are parsing a long array you can 123 get the same effect by setting rootArrayItems to YES: 124 125 id parser = [SBJson4Parser unwrapRootArrayParserWithBlock:block 126 errorHandler:eh]; 127 128 // Note that this input contains A SINGLE top-level document 129 id data = [@"[[],{},[],{}]" dataWithEncoding:NSUTF8StringEncoding]; 130 [parser parse:data]; 131 132 @note Stream based parsing does mean that you lose some of the correctness 133 verification you would have with a parser that considered the entire input 134 before returning an answer. It is technically possible to have some parts 135 of a document returned *as if they were correct* but then encounter an error 136 in a later part of the document. You should keep this in mind when 137 considering whether it would suit your application. 138 139 140 */ 141 @interface SBJson4Parser : NSObject 142 143 /** 144 Create a JSON Parser. 145 146 This can be used to create a parser that accepts only one document, or one that parses 147 many documents any 148 149 @param block Called for each element. Set *stop to `YES` if you have seen 150 enough and would like to skip the rest of the elements. 151 152 @param allowMultiRoot Indicate that you are expecting multiple whitespace-separated 153 JSON documents, similar to what Twitter uses. 154 155 @param unwrapRootArray If set the parser will pretend an root array does not exist 156 and the enumerator block will be called once for each item in it. This option 157 does nothing if the the JSON has an object at its root. 158 159 @param eh Called if the parser encounters an error. 160 161 @see -unwrapRootArrayParserWithBlock:errorHandler: 162 @see -multiRootParserWithBlock:errorHandler: 163 @see -initWithBlock:processBlock:multiRoot:unwrapRootArray:maxDepth:errorHandler: 164 165 */ 166 + (id)parserWithBlock:(SBJson4ValueBlock)block 167 allowMultiRoot:(BOOL)allowMultiRoot 168 unwrapRootArray:(BOOL)unwrapRootArray 169 errorHandler:(SBJson4ErrorBlock)eh; 170 171 172 /** 173 Create a JSON Parser that parses multiple whitespace separated documents. 174 This is useful for something like Twitter's feed, which gives you one JSON 175 document per line. 176 177 @param block Called for each element. Set *stop to `YES` if you have seen 178 enough and would like to skip the rest of the elements. 179 180 @param eh Called if the parser encounters an error. 181 182 @see +unwrapRootArrayParserWithBlock:errorHandler: 183 @see +parserWithBlock:allowMultiRoot:unwrapRootArray:errorHandler: 184 @see -initWithBlock:processBlock:multiRoot:unwrapRootArray:maxDepth:errorHandler: 185 */ 186 + (id)multiRootParserWithBlock:(SBJson4ValueBlock)block 187 errorHandler:(SBJson4ErrorBlock)eh; 188 189 /** 190 Create a JSON Parser that parses a huge array and calls for the value block for 191 each element in the outermost array. 192 193 @param block Called for each element. Set *stop to `YES` if you have seen 194 enough and would like to skip the rest of the elements. 195 196 @param eh Called if the parser encounters an error. 197 198 @see +multiRootParserWithBlock:errorHandler: 199 @see +parserWithBlock:allowMultiRoot:unwrapRootArray:errorHandler: 200 @see -initWithBlock:processBlock:multiRoot:unwrapRootArray:maxDepth:errorHandler: 201 */ 202 + (id)unwrapRootArrayParserWithBlock:(SBJson4ValueBlock)block 203 errorHandler:(SBJson4ErrorBlock)eh; 204 205 /** 206 Create a JSON Parser. 207 208 @param block Called for each element. Set *stop to `YES` if you have seen 209 enough and would like to skip the rest of the elements. 210 211 @param processBlock A block that allows you to process individual values before being 212 returned. 213 214 @param multiRoot Indicate that you are expecting multiple whitespace-separated 215 JSON documents, similar to what Twitter uses. 216 217 @param unwrapRootArray If set the parser will pretend an root array does not exist 218 and the enumerator block will be called once for each item in it. This option 219 does nothing if the the JSON has an object at its root. 220 221 @param maxDepth The max recursion depth of the parser. Defaults to 32. 222 223 @param eh Called if the parser encounters an error. 224 225 */ 226 - (id)initWithBlock:(SBJson4ValueBlock)block 227 processBlock:(SBJson4ProcessBlock)processBlock 228 multiRoot:(BOOL)multiRoot 229 unwrapRootArray:(BOOL)unwrapRootArray 230 maxDepth:(NSUInteger)maxDepth 231 errorHandler:(SBJson4ErrorBlock)eh; 232 233 /** 234 Parse some JSON 235 236 The JSON is assumed to be UTF8 encoded. This can be a full JSON document, or a part of one. 237 238 @param data An NSData object containing the next chunk of JSON 239 240 @return 241 - SBJson4ParserComplete if a full document was found 242 - SBJson4ParserWaitingForData if a partial document was found and more data is required to complete it 243 - SBJson4ParserError if an error occurred. 244 245 */ 246 - (SBJson4ParserStatus)parse:(NSData*)data; 247 248 @end