diff options
Diffstat (limited to 'Classes/Source/JSON/CJSONSerializer.m')
-rw-r--r-- | Classes/Source/JSON/CJSONSerializer.m | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/Classes/Source/JSON/CJSONSerializer.m b/Classes/Source/JSON/CJSONSerializer.m new file mode 100644 index 0000000..952b3c2 --- /dev/null +++ b/Classes/Source/JSON/CJSONSerializer.m @@ -0,0 +1,342 @@ +// +// CJSONSerializer.m +// TouchCode +// +// Created by Jonathan Wight on 12/07/2005. +// Copyright 2005 toxicsoftware.com. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#import "CJSONSerializer.h" + +#import "JSONRepresentation.h" + +static NSData *kNULL = NULL; +static NSData *kFalse = NULL; +static NSData *kTrue = NULL; + +@implementation CJSONSerializer + ++ (void)initialize + { + NSAutoreleasePool *thePool = [[NSAutoreleasePool alloc] init]; + + if (self == [CJSONSerializer class]) + { + if (kNULL == NULL) + kNULL = [[NSData alloc] initWithBytesNoCopy:(void *)"null" length:4 freeWhenDone:NO]; + if (kFalse == NULL) + kFalse = [[NSData alloc] initWithBytesNoCopy:(void *)"false" length:5 freeWhenDone:NO]; + if (kTrue == NULL) + kTrue = [[NSData alloc] initWithBytesNoCopy:(void *)"true" length:4 freeWhenDone:NO]; + + [thePool release]; + } + } + ++ (id)serializer + { + return([[[self alloc] init] autorelease]); + } + +- (BOOL)isValidJSONObject:(id)inObject + { + if ([inObject isKindOfClass:[NSNull class]]) + { + return(YES); + } + else if ([inObject isKindOfClass:[NSNumber class]]) + { + return(YES); + } + else if ([inObject isKindOfClass:[NSString class]]) + { + return(YES); + } + else if ([inObject isKindOfClass:[NSArray class]]) + { + return(YES); + } + else if ([inObject isKindOfClass:[NSDictionary class]]) + { + return(YES); + } + else if ([inObject isKindOfClass:[NSData class]]) + { + return(YES); + } + else if ([inObject respondsToSelector:@selector(JSONDataRepresentation)]) + { + return(YES); + } + else + { + return(NO); + } + } + +- (NSData *)serializeObject:(id)inObject error:(NSError **)outError + { + NSData *theResult = NULL; + + if ([inObject isKindOfClass:[NSNull class]]) + { + theResult = [self serializeNull:inObject error:outError]; + } + else if ([inObject isKindOfClass:[NSNumber class]]) + { + theResult = [self serializeNumber:inObject error:outError]; + } + else if ([inObject isKindOfClass:[NSString class]]) + { + theResult = [self serializeString:inObject error:outError]; + } + else if ([inObject isKindOfClass:[NSArray class]]) + { + theResult = [self serializeArray:inObject error:outError]; + } + else if ([inObject isKindOfClass:[NSDictionary class]]) + { + theResult = [self serializeDictionary:inObject error:outError]; + } + else if ([inObject isKindOfClass:[NSData class]]) + { + NSString *theString = [[[NSString alloc] initWithData:inObject encoding:NSUTF8StringEncoding] autorelease]; + theResult = [self serializeString:theString error:outError]; + } + else if ([inObject respondsToSelector:@selector(JSONDataRepresentation)]) + { + theResult = [inObject JSONDataRepresentation]; + } + else + { + if (outError) + { + NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithFormat:@"Cannot serialize data of type '%@'", NSStringFromClass([inObject class])], NSLocalizedDescriptionKey, + NULL]; + *outError = [NSError errorWithDomain:@"TODO_DOMAIN" code:CJSONSerializerErrorCouldNotSerializeDataType userInfo:theUserInfo]; + } + return(NULL); + } + if (theResult == NULL) + { + if (outError) + { + NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithFormat:@"Could not serialize object '%@'", inObject], NSLocalizedDescriptionKey, + NULL]; + *outError = [NSError errorWithDomain:@"TODO_DOMAIN" code:CJSONSerializerErrorCouldNotSerializeObject userInfo:theUserInfo]; + } + return(NULL); + } + return(theResult); + } + +- (NSData *)serializeNull:(NSNull *)inNull error:(NSError **)outError + { + #pragma unused (inNull, outError) + return(kNULL); + } + +- (NSData *)serializeNumber:(NSNumber *)inNumber error:(NSError **)outError + { + #pragma unused (outError) + NSData *theResult = NULL; + switch (CFNumberGetType((CFNumberRef)inNumber)) + { + case kCFNumberCharType: + { + int theValue = [inNumber intValue]; + if (theValue == 0) + theResult = kFalse; + else if (theValue == 1) + theResult = kTrue; + else + theResult = [[inNumber stringValue] dataUsingEncoding:NSASCIIStringEncoding]; + } + break; + case kCFNumberFloat32Type: + case kCFNumberFloat64Type: + case kCFNumberFloatType: + case kCFNumberDoubleType: + case kCFNumberSInt8Type: + case kCFNumberSInt16Type: + case kCFNumberSInt32Type: + case kCFNumberSInt64Type: + case kCFNumberShortType: + case kCFNumberIntType: + case kCFNumberLongType: + case kCFNumberLongLongType: + case kCFNumberCFIndexType: + default: + theResult = [[inNumber stringValue] dataUsingEncoding:NSASCIIStringEncoding]; + break; + } + return(theResult); + } + +- (NSData *)serializeString:(NSString *)inString error:(NSError **)outError + { + #pragma unused (outError) + + const char *theUTF8String = [inString UTF8String]; + + NSMutableData *theData = [NSMutableData dataWithLength:strlen(theUTF8String) * 2 + 2]; + + char *theOutputStart = [theData mutableBytes]; + char *OUT = theOutputStart; + + *OUT++ = '"'; + + for (const char *IN = theUTF8String; IN && *IN != '\0'; ++IN) + { + switch (*IN) + { + case '\\': + { + *OUT++ = '\\'; + *OUT++ = '\\'; + } + break; + case '\"': + { + *OUT++ = '\\'; + *OUT++ = '\"'; + } + break; + case '/': + { + *OUT++ = '\\'; + *OUT++ = '/'; + } + break; + case '\b': + { + *OUT++ = '\\'; + *OUT++ = 'b'; + } + break; + case '\f': + { + *OUT++ = '\\'; + *OUT++ = 'f'; + } + break; + case '\n': + { + *OUT++ = '\\'; + *OUT++ = 'n'; + } + break; + case '\r': + { + *OUT++ = '\\'; + *OUT++ = 'r'; + } + break; + case '\t': + { + *OUT++ = '\\'; + *OUT++ = 't'; + } + break; + default: + { + *OUT++ = *IN; + } + break; + } + } + + *OUT++ = '"'; + + theData.length = OUT - theOutputStart; + return(theData); + } + +- (NSData *)serializeArray:(NSArray *)inArray error:(NSError **)outError + { + NSMutableData *theData = [NSMutableData data]; + + [theData appendBytes:"[" length:1]; + + NSEnumerator *theEnumerator = [inArray objectEnumerator]; + id theValue = NULL; + NSUInteger i = 0; + while ((theValue = [theEnumerator nextObject]) != NULL) + { + NSData *theValueData = [self serializeObject:theValue error:outError]; + if (theValueData == NULL) + { + return(NULL); + } + [theData appendData:theValueData]; + if (++i < [inArray count]) + [theData appendBytes:"," length:1]; + } + + [theData appendBytes:"]" length:1]; + + return(theData); + } + +- (NSData *)serializeDictionary:(NSDictionary *)inDictionary error:(NSError **)outError + { + NSMutableData *theData = [NSMutableData data]; + + [theData appendBytes:"{" length:1]; + + NSArray *theKeys = [inDictionary allKeys]; + NSEnumerator *theEnumerator = [theKeys objectEnumerator]; + NSString *theKey = NULL; + while ((theKey = [theEnumerator nextObject]) != NULL) + { + id theValue = [inDictionary objectForKey:theKey]; + + NSData *theKeyData = [self serializeString:theKey error:outError]; + if (theKeyData == NULL) + { + return(NULL); + } + NSData *theValueData = [self serializeObject:theValue error:outError]; + if (theValueData == NULL) + { + return(NULL); + } + + + [theData appendData:theKeyData]; + [theData appendBytes:":" length:1]; + [theData appendData:theValueData]; + + if (theKey != [theKeys lastObject]) + [theData appendData:[@"," dataUsingEncoding:NSASCIIStringEncoding]]; + } + + [theData appendBytes:"}" length:1]; + + return(theData); + } + +@end |