summaryrefslogtreecommitdiffstats
path: root/Classes/Source/JSON/CJSONSerializer.m
diff options
context:
space:
mode:
Diffstat (limited to 'Classes/Source/JSON/CJSONSerializer.m')
-rw-r--r--Classes/Source/JSON/CJSONSerializer.m342
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