Playlist Generator
1.0
|
00001 /* 00002 Copyright (c) 2010, Stig Brautaset. 00003 All rights reserved. 00004 00005 Redistribution and use in source and binary forms, with or without 00006 modification, are permitted provided that the following conditions are 00007 met: 00008 00009 Redistributions of source code must retain the above copyright 00010 notice, this list of conditions and the following disclaimer. 00011 00012 Redistributions in binary form must reproduce the above copyright 00013 notice, this list of conditions and the following disclaimer in the 00014 documentation and/or other materials provided with the distribution. 00015 00016 Neither the name of the the author nor the names of its contributors 00017 may be used to endorse or promote products derived from this software 00018 without specific prior written permission. 00019 00020 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 00021 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 00022 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 00023 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00024 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00025 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00026 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00027 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00028 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00029 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00030 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 */ 00032 00033 #import "SBJsonStreamWriter.h" 00034 #import "SBJsonStreamWriterState.h" 00035 00036 static NSNumber *kNotANumber; 00037 static NSNumber *kTrue; 00038 static NSNumber *kFalse; 00039 static NSNumber *kPositiveInfinity; 00040 static NSNumber *kNegativeInfinity; 00041 00042 00043 @implementation SBJsonStreamWriter 00044 00045 @synthesize error; 00046 @synthesize maxDepth; 00047 @synthesize state; 00048 @synthesize stateStack; 00049 @synthesize humanReadable; 00050 @synthesize sortKeys; 00051 00052 + (void)initialize { 00053 kNotANumber = [NSDecimalNumber notANumber]; 00054 kPositiveInfinity = [NSNumber numberWithDouble:+INFINITY]; 00055 kNegativeInfinity = [NSNumber numberWithDouble:-INFINITY]; 00056 kTrue = [NSNumber numberWithBool:YES]; 00057 kFalse = [NSNumber numberWithBool:NO]; 00058 } 00059 00060 #pragma mark Housekeeping 00061 00062 @synthesize delegate; 00063 00064 - (id)init { 00065 self = [super init]; 00066 if (self) { 00067 maxDepth = 32u; 00068 stateStack = [[NSMutableArray alloc] initWithCapacity:maxDepth]; 00069 state = [SBJsonStreamWriterStateStart sharedInstance]; 00070 cache = [[NSMutableDictionary alloc] initWithCapacity:32]; 00071 } 00072 return self; 00073 } 00074 00075 - (void)dealloc { 00076 self.state = nil; 00077 } 00078 00079 #pragma mark Methods 00080 00081 - (void)appendBytes:(const void *)bytes length:(NSUInteger)length { 00082 [delegate writer:self appendBytes:bytes length:length]; 00083 } 00084 00085 - (BOOL)writeObject:(NSDictionary *)dict { 00086 if (![self writeObjectOpen]) 00087 return NO; 00088 00089 NSArray *keys = [dict allKeys]; 00090 if (sortKeys) 00091 keys = [keys sortedArrayUsingSelector:@selector(compare:)]; 00092 00093 for (id k in keys) { 00094 if (![k isKindOfClass:[NSString class]]) { 00095 self.error = [NSString stringWithFormat:@"JSON object key must be string: %@", k]; 00096 return NO; 00097 } 00098 00099 if (![self writeString:k]) 00100 return NO; 00101 if (![self writeValue:[dict objectForKey:k]]) 00102 return NO; 00103 } 00104 00105 return [self writeObjectClose]; 00106 } 00107 00108 - (BOOL)writeArray:(NSArray*)array { 00109 if (![self writeArrayOpen]) 00110 return NO; 00111 for (id v in array) 00112 if (![self writeValue:v]) 00113 return NO; 00114 return [self writeArrayClose]; 00115 } 00116 00117 00118 - (BOOL)writeObjectOpen { 00119 if ([state isInvalidState:self]) return NO; 00120 if ([state expectingKey:self]) return NO; 00121 [state appendSeparator:self]; 00122 if (humanReadable && stateStack.count) [state appendWhitespace:self]; 00123 00124 [stateStack addObject:state]; 00125 self.state = [SBJsonStreamWriterStateObjectStart sharedInstance]; 00126 00127 if (maxDepth && stateStack.count > maxDepth) { 00128 self.error = @"Nested too deep"; 00129 return NO; 00130 } 00131 00132 [delegate writer:self appendBytes:"{" length:1]; 00133 return YES; 00134 } 00135 00136 - (BOOL)writeObjectClose { 00137 if ([state isInvalidState:self]) return NO; 00138 00139 SBJsonStreamWriterState *prev = state; 00140 00141 self.state = [stateStack lastObject]; 00142 [stateStack removeLastObject]; 00143 00144 if (humanReadable) [prev appendWhitespace:self]; 00145 [delegate writer:self appendBytes:"}" length:1]; 00146 00147 [state transitionState:self]; 00148 return YES; 00149 } 00150 00151 - (BOOL)writeArrayOpen { 00152 if ([state isInvalidState:self]) return NO; 00153 if ([state expectingKey:self]) return NO; 00154 [state appendSeparator:self]; 00155 if (humanReadable && stateStack.count) [state appendWhitespace:self]; 00156 00157 [stateStack addObject:state]; 00158 self.state = [SBJsonStreamWriterStateArrayStart sharedInstance]; 00159 00160 if (maxDepth && stateStack.count > maxDepth) { 00161 self.error = @"Nested too deep"; 00162 return NO; 00163 } 00164 00165 [delegate writer:self appendBytes:"[" length:1]; 00166 return YES; 00167 } 00168 00169 - (BOOL)writeArrayClose { 00170 if ([state isInvalidState:self]) return NO; 00171 if ([state expectingKey:self]) return NO; 00172 00173 SBJsonStreamWriterState *prev = state; 00174 00175 self.state = [stateStack lastObject]; 00176 [stateStack removeLastObject]; 00177 00178 if (humanReadable) [prev appendWhitespace:self]; 00179 [delegate writer:self appendBytes:"]" length:1]; 00180 00181 [state transitionState:self]; 00182 return YES; 00183 } 00184 00185 - (BOOL)writeNull { 00186 if ([state isInvalidState:self]) return NO; 00187 if ([state expectingKey:self]) return NO; 00188 [state appendSeparator:self]; 00189 if (humanReadable) [state appendWhitespace:self]; 00190 00191 [delegate writer:self appendBytes:"null" length:4]; 00192 [state transitionState:self]; 00193 return YES; 00194 } 00195 00196 - (BOOL)writeBool:(BOOL)x { 00197 if ([state isInvalidState:self]) return NO; 00198 if ([state expectingKey:self]) return NO; 00199 [state appendSeparator:self]; 00200 if (humanReadable) [state appendWhitespace:self]; 00201 00202 if (x) 00203 [delegate writer:self appendBytes:"true" length:4]; 00204 else 00205 [delegate writer:self appendBytes:"false" length:5]; 00206 [state transitionState:self]; 00207 return YES; 00208 } 00209 00210 00211 - (BOOL)writeValue:(id)o { 00212 if ([o isKindOfClass:[NSDictionary class]]) { 00213 return [self writeObject:o]; 00214 00215 } else if ([o isKindOfClass:[NSArray class]]) { 00216 return [self writeArray:o]; 00217 00218 } else if ([o isKindOfClass:[NSString class]]) { 00219 [self writeString:o]; 00220 return YES; 00221 00222 } else if ([o isKindOfClass:[NSNumber class]]) { 00223 return [self writeNumber:o]; 00224 00225 } else if ([o isKindOfClass:[NSNull class]]) { 00226 return [self writeNull]; 00227 00228 } else if ([o respondsToSelector:@selector(proxyForJson)]) { 00229 return [self writeValue:[o proxyForJson]]; 00230 00231 } 00232 00233 self.error = [NSString stringWithFormat:@"JSON serialisation not supported for %@", [o class]]; 00234 return NO; 00235 } 00236 00237 static const char *strForChar(int c) { 00238 switch (c) { 00239 case 0: return "\\u0000"; break; 00240 case 1: return "\\u0001"; break; 00241 case 2: return "\\u0002"; break; 00242 case 3: return "\\u0003"; break; 00243 case 4: return "\\u0004"; break; 00244 case 5: return "\\u0005"; break; 00245 case 6: return "\\u0006"; break; 00246 case 7: return "\\u0007"; break; 00247 case 8: return "\\b"; break; 00248 case 9: return "\\t"; break; 00249 case 10: return "\\n"; break; 00250 case 11: return "\\u000b"; break; 00251 case 12: return "\\f"; break; 00252 case 13: return "\\r"; break; 00253 case 14: return "\\u000e"; break; 00254 case 15: return "\\u000f"; break; 00255 case 16: return "\\u0010"; break; 00256 case 17: return "\\u0011"; break; 00257 case 18: return "\\u0012"; break; 00258 case 19: return "\\u0013"; break; 00259 case 20: return "\\u0014"; break; 00260 case 21: return "\\u0015"; break; 00261 case 22: return "\\u0016"; break; 00262 case 23: return "\\u0017"; break; 00263 case 24: return "\\u0018"; break; 00264 case 25: return "\\u0019"; break; 00265 case 26: return "\\u001a"; break; 00266 case 27: return "\\u001b"; break; 00267 case 28: return "\\u001c"; break; 00268 case 29: return "\\u001d"; break; 00269 case 30: return "\\u001e"; break; 00270 case 31: return "\\u001f"; break; 00271 case 34: return "\\\""; break; 00272 case 92: return "\\\\"; break; 00273 } 00274 NSLog(@"FUTFUTFUT: -->'%c'<---", c); 00275 return "FUTFUTFUT"; 00276 } 00277 00278 - (BOOL)writeString:(NSString*)string { 00279 if ([state isInvalidState:self]) return NO; 00280 [state appendSeparator:self]; 00281 if (humanReadable) [state appendWhitespace:self]; 00282 00283 NSMutableData *buf = [cache objectForKey:string]; 00284 if (!buf) { 00285 00286 NSUInteger len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 00287 const char *utf8 = [string UTF8String]; 00288 NSUInteger written = 0, i = 0; 00289 00290 buf = [NSMutableData dataWithCapacity:(NSUInteger)(len * 1.1f)]; 00291 [buf appendBytes:"\"" length:1]; 00292 00293 for (i = 0; i < len; i++) { 00294 int c = utf8[i]; 00295 BOOL isControlChar = c >= 0 && c < 32; 00296 if (isControlChar || c == '"' || c == '\\') { 00297 if (i - written) 00298 [buf appendBytes:utf8 + written length:i - written]; 00299 written = i + 1; 00300 00301 const char *t = strForChar(c); 00302 [buf appendBytes:t length:strlen(t)]; 00303 } 00304 } 00305 00306 if (i - written) 00307 [buf appendBytes:utf8 + written length:i - written]; 00308 00309 [buf appendBytes:"\"" length:1]; 00310 [cache setObject:buf forKey:string]; 00311 } 00312 00313 [delegate writer:self appendBytes:[buf bytes] length:[buf length]]; 00314 [state transitionState:self]; 00315 return YES; 00316 } 00317 00318 - (BOOL)writeNumber:(NSNumber*)number { 00319 if (number == kTrue || number == kFalse) 00320 return [self writeBool:[number boolValue]]; 00321 00322 if ([state isInvalidState:self]) return NO; 00323 if ([state expectingKey:self]) return NO; 00324 [state appendSeparator:self]; 00325 if (humanReadable) [state appendWhitespace:self]; 00326 00327 if ([kPositiveInfinity isEqualToNumber:number]) { 00328 self.error = @"+Infinity is not a valid number in JSON"; 00329 return NO; 00330 00331 } else if ([kNegativeInfinity isEqualToNumber:number]) { 00332 self.error = @"-Infinity is not a valid number in JSON"; 00333 return NO; 00334 00335 } else if ([kNotANumber isEqualToNumber:number]) { 00336 self.error = @"NaN is not a valid number in JSON"; 00337 return NO; 00338 } 00339 00340 const char *objcType = [number objCType]; 00341 char num[128]; 00342 size_t len; 00343 00344 switch (objcType[0]) { 00345 case 'c': case 'i': case 's': case 'l': case 'q': 00346 len = snprintf(num, sizeof num, "%lld", [number longLongValue]); 00347 break; 00348 case 'C': case 'I': case 'S': case 'L': case 'Q': 00349 len = snprintf(num, sizeof num, "%llu", [number unsignedLongLongValue]); 00350 break; 00351 case 'f': case 'd': default: 00352 if ([number isKindOfClass:[NSDecimalNumber class]]) { 00353 char const *utf8 = [[number stringValue] UTF8String]; 00354 [delegate writer:self appendBytes:utf8 length: strlen(utf8)]; 00355 [state transitionState:self]; 00356 return YES; 00357 } 00358 len = snprintf(num, sizeof num, "%.17g", [number doubleValue]); 00359 break; 00360 } 00361 [delegate writer:self appendBytes:num length: len]; 00362 [state transitionState:self]; 00363 return YES; 00364 } 00365 00366 @end