add .gitignore
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright (C) 2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "SBJsonBase.h"
|
||||
NSString * SBJSONErrorDomain = @"org.brautaset.JSON.ErrorDomain";
|
||||
|
||||
|
||||
@implementation SBJsonBase
|
||||
|
||||
@synthesize errorTrace;
|
||||
@synthesize maxDepth;
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self)
|
||||
self.maxDepth = 512;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[errorTrace release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str {
|
||||
NSDictionary *userInfo;
|
||||
if (!errorTrace) {
|
||||
errorTrace = [NSMutableArray new];
|
||||
userInfo = [NSDictionary dictionaryWithObject:str forKey:NSLocalizedDescriptionKey];
|
||||
|
||||
} else {
|
||||
userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
str, NSLocalizedDescriptionKey,
|
||||
[errorTrace lastObject], NSUnderlyingErrorKey,
|
||||
nil];
|
||||
}
|
||||
|
||||
NSError *error = [NSError errorWithDomain:SBJSONErrorDomain code:code userInfo:userInfo];
|
||||
|
||||
[self willChangeValueForKey:@"errorTrace"];
|
||||
[errorTrace addObject:error];
|
||||
[self didChangeValueForKey:@"errorTrace"];
|
||||
}
|
||||
|
||||
- (void)clearErrorTrace {
|
||||
[self willChangeValueForKey:@"errorTrace"];
|
||||
[errorTrace release];
|
||||
errorTrace = nil;
|
||||
[self didChangeValueForKey:@"errorTrace"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright (C) 2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SBJsonBase.h"
|
||||
|
||||
/**
|
||||
@brief Options for the parser class.
|
||||
|
||||
This exists so the SBJSON facade can implement the options in the parser without having to re-declare them.
|
||||
*/
|
||||
@protocol SBJsonParser
|
||||
|
||||
/**
|
||||
@brief Return the object represented by the given string.
|
||||
|
||||
Returns the object represented by the passed-in string or nil on error. The returned object can be
|
||||
a string, number, boolean, null, array or dictionary.
|
||||
|
||||
@param repr the json string to parse
|
||||
*/
|
||||
- (id)objectWithString:(NSString *)repr;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
@brief The JSON parser class.
|
||||
|
||||
JSON is mapped to Objective-C types in the following way:
|
||||
|
||||
@li Null -> NSNull
|
||||
@li String -> NSMutableString
|
||||
@li Array -> NSMutableArray
|
||||
@li Object -> NSMutableDictionary
|
||||
@li Boolean -> NSNumber (initialised with -initWithBool:)
|
||||
@li Number -> NSDecimalNumber
|
||||
|
||||
Since Objective-C doesn't have a dedicated class for boolean values, these turns into NSNumber
|
||||
instances. These are initialised with the -initWithBool: method, and
|
||||
round-trip back to JSON properly. (They won't silently suddenly become 0 or 1; they'll be
|
||||
represented as 'true' and 'false' again.)
|
||||
|
||||
JSON numbers turn into NSDecimalNumber instances,
|
||||
as we can thus avoid any loss of precision. (JSON allows ridiculously large numbers.)
|
||||
|
||||
*/
|
||||
@interface SBJsonParser : SBJsonBase <SBJsonParser> {
|
||||
|
||||
@private
|
||||
const char *c;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// don't use - exists for backwards compatibility with 2.1.x only. Will be removed in 2.3.
|
||||
@interface SBJsonParser (Private)
|
||||
- (id)fragmentWithString:(id)repr;
|
||||
@end
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright (C) 2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
@brief Adds JSON parsing methods to NSString
|
||||
|
||||
This is a category on NSString that adds methods for parsing the target string.
|
||||
*/
|
||||
@interface NSString (NSString_SBJSON)
|
||||
|
||||
|
||||
/**
|
||||
@brief Returns the object represented in the receiver, or nil on error.
|
||||
|
||||
Returns a a scalar object represented by the string's JSON fragment representation.
|
||||
|
||||
@deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
|
||||
*/
|
||||
- (id)JSONFragmentValue;
|
||||
|
||||
/**
|
||||
@brief Returns the NSDictionary or NSArray represented by the current string's JSON representation.
|
||||
|
||||
Returns the dictionary or array represented in the receiver, or nil on error.
|
||||
|
||||
Returns the NSDictionary or NSArray represented by the current string's JSON representation.
|
||||
*/
|
||||
- (id)JSONValue;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
Copyright (C) 2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "SBJsonWriter.h"
|
||||
|
||||
@interface SBJsonWriter ()
|
||||
|
||||
- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json;
|
||||
- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json;
|
||||
- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json;
|
||||
- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json;
|
||||
|
||||
- (NSString*)indent;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SBJsonWriter
|
||||
|
||||
static NSMutableCharacterSet *kEscapeChars;
|
||||
|
||||
+ (void)initialize {
|
||||
kEscapeChars = [[NSMutableCharacterSet characterSetWithRange: NSMakeRange(0,32)] retain];
|
||||
[kEscapeChars addCharactersInString: @"\"\\"];
|
||||
}
|
||||
|
||||
|
||||
@synthesize sortKeys;
|
||||
@synthesize humanReadable;
|
||||
|
||||
/**
|
||||
@deprecated This exists in order to provide fragment support in older APIs in one more version.
|
||||
It should be removed in the next major version.
|
||||
*/
|
||||
- (NSString*)stringWithFragment:(id)value {
|
||||
[self clearErrorTrace];
|
||||
depth = 0;
|
||||
NSMutableString *json = [NSMutableString stringWithCapacity:128];
|
||||
|
||||
if ([self appendValue:value into:json])
|
||||
return json;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSString*)stringWithObject:(id)value {
|
||||
|
||||
if ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]) {
|
||||
return [self stringWithFragment:value];
|
||||
}
|
||||
|
||||
if ([value respondsToSelector:@selector(proxyForJson)]) {
|
||||
NSString *tmp = [self stringWithObject:[value proxyForJson]];
|
||||
if (tmp)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
[self clearErrorTrace];
|
||||
[self addErrorWithCode:EFRAGMENT description:@"Not valid type for JSON"];
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSString*)indent {
|
||||
return [@"\n" stringByPaddingToLength:1 + 2 * depth withString:@" " startingAtIndex:0];
|
||||
}
|
||||
|
||||
- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json {
|
||||
if ([fragment isKindOfClass:[NSDictionary class]]) {
|
||||
if (![self appendDictionary:fragment into:json])
|
||||
return NO;
|
||||
|
||||
} else if ([fragment isKindOfClass:[NSArray class]]) {
|
||||
if (![self appendArray:fragment into:json])
|
||||
return NO;
|
||||
|
||||
} else if ([fragment isKindOfClass:[NSString class]]) {
|
||||
if (![self appendString:fragment into:json])
|
||||
return NO;
|
||||
|
||||
} else if ([fragment isKindOfClass:[NSNumber class]]) {
|
||||
if ('c' == *[fragment objCType])
|
||||
[json appendString:[fragment boolValue] ? @"true" : @"false"];
|
||||
else
|
||||
[json appendString:[fragment stringValue]];
|
||||
|
||||
} else if ([fragment isKindOfClass:[NSNull class]]) {
|
||||
[json appendString:@"null"];
|
||||
} else if ([fragment respondsToSelector:@selector(proxyForJson)]) {
|
||||
[self appendValue:[fragment proxyForJson] into:json];
|
||||
|
||||
} else {
|
||||
[self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"JSON serialisation not supported for %@", [fragment class]]];
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json {
|
||||
if (maxDepth && ++depth > maxDepth) {
|
||||
[self addErrorWithCode:EDEPTH description: @"Nested too deep"];
|
||||
return NO;
|
||||
}
|
||||
[json appendString:@"["];
|
||||
|
||||
BOOL addComma = NO;
|
||||
for (id value in fragment) {
|
||||
if (addComma)
|
||||
[json appendString:@","];
|
||||
else
|
||||
addComma = YES;
|
||||
|
||||
if ([self humanReadable])
|
||||
[json appendString:[self indent]];
|
||||
|
||||
if (![self appendValue:value into:json]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
depth--;
|
||||
if ([self humanReadable] && [fragment count])
|
||||
[json appendString:[self indent]];
|
||||
[json appendString:@"]"];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json {
|
||||
if (maxDepth && ++depth > maxDepth) {
|
||||
[self addErrorWithCode:EDEPTH description: @"Nested too deep"];
|
||||
return NO;
|
||||
}
|
||||
[json appendString:@"{"];
|
||||
|
||||
NSString *colon = [self humanReadable] ? @" : " : @":";
|
||||
BOOL addComma = NO;
|
||||
NSArray *keys = [fragment allKeys];
|
||||
if (self.sortKeys)
|
||||
keys = [keys sortedArrayUsingSelector:@selector(compare:)];
|
||||
|
||||
for (id value in keys) {
|
||||
if (addComma)
|
||||
[json appendString:@","];
|
||||
else
|
||||
addComma = YES;
|
||||
|
||||
if ([self humanReadable])
|
||||
[json appendString:[self indent]];
|
||||
|
||||
if (![value isKindOfClass:[NSString class]]) {
|
||||
[self addErrorWithCode:EUNSUPPORTED description: @"JSON object key must be string"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (![self appendString:value into:json])
|
||||
return NO;
|
||||
|
||||
[json appendString:colon];
|
||||
if (![self appendValue:[fragment objectForKey:value] into:json]) {
|
||||
[self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"Unsupported value for key %@ in object", value]];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
depth--;
|
||||
if ([self humanReadable] && [fragment count])
|
||||
[json appendString:[self indent]];
|
||||
[json appendString:@"}"];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json {
|
||||
|
||||
[json appendString:@"\""];
|
||||
|
||||
NSRange esc = [fragment rangeOfCharacterFromSet:kEscapeChars];
|
||||
if ( !esc.length ) {
|
||||
// No special chars -- can just add the raw string:
|
||||
[json appendString:fragment];
|
||||
|
||||
} else {
|
||||
NSUInteger length = [fragment length];
|
||||
for (NSUInteger i = 0; i < length; i++) {
|
||||
unichar uc = [fragment characterAtIndex:i];
|
||||
switch (uc) {
|
||||
case '"': [json appendString:@"\\\""]; break;
|
||||
case '\\': [json appendString:@"\\\\"]; break;
|
||||
case '\t': [json appendString:@"\\t"]; break;
|
||||
case '\n': [json appendString:@"\\n"]; break;
|
||||
case '\r': [json appendString:@"\\r"]; break;
|
||||
case '\b': [json appendString:@"\\b"]; break;
|
||||
case '\f': [json appendString:@"\\f"]; break;
|
||||
default:
|
||||
if (uc < 0x20) {
|
||||
[json appendFormat:@"\\u%04x", uc];
|
||||
} else {
|
||||
CFStringAppendCharacters((CFMutableStringRef)json, &uc, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[json appendString:@"\""];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright (C) 2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern NSString * SBJSONErrorDomain;
|
||||
|
||||
|
||||
enum {
|
||||
EUNSUPPORTED = 1,
|
||||
EPARSENUM,
|
||||
EPARSE,
|
||||
EFRAGMENT,
|
||||
ECTRL,
|
||||
EUNICODE,
|
||||
EDEPTH,
|
||||
EESCAPE,
|
||||
ETRAILCOMMA,
|
||||
ETRAILGARBAGE,
|
||||
EEOF,
|
||||
EINPUT
|
||||
};
|
||||
|
||||
/**
|
||||
@brief Common base class for parsing & writing.
|
||||
|
||||
This class contains the common error-handling code and option between the parser/writer.
|
||||
*/
|
||||
@interface SBJsonBase : NSObject {
|
||||
NSMutableArray *errorTrace;
|
||||
|
||||
@protected
|
||||
NSUInteger depth, maxDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief The maximum recursing depth.
|
||||
|
||||
Defaults to 512. If the input is nested deeper than this the input will be deemed to be
|
||||
malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can
|
||||
turn off this security feature by setting the maxDepth value to 0.
|
||||
*/
|
||||
@property NSUInteger maxDepth;
|
||||
|
||||
/**
|
||||
@brief Return an error trace, or nil if there was no errors.
|
||||
|
||||
Note that this method returns the trace of the last method that failed.
|
||||
You need to check the return value of the call you're making to figure out
|
||||
if the call actually failed, before you know call this method.
|
||||
*/
|
||||
@property(copy,readonly) NSArray* errorTrace;
|
||||
|
||||
/// @internal for use in subclasses to add errors to the stack trace
|
||||
- (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str;
|
||||
|
||||
/// @internal for use in subclasess to clear the error before a new parsing attempt
|
||||
- (void)clearErrorTrace;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright (C) 2007-2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "NSString+SBJSON.h"
|
||||
#import "SBJsonParser.h"
|
||||
|
||||
@implementation NSString (NSString_SBJSON)
|
||||
|
||||
- (id)JSONFragmentValue
|
||||
{
|
||||
SBJsonParser *jsonParser = [SBJsonParser new];
|
||||
id repr = [jsonParser fragmentWithString:self];
|
||||
if (!repr)
|
||||
//CCLOG(@"-JSONFragmentValue failed. Error trace is: %@", [jsonParser errorTrace]);
|
||||
[jsonParser release];
|
||||
return repr;
|
||||
}
|
||||
|
||||
- (id)JSONValue
|
||||
{
|
||||
SBJsonParser *jsonParser = [SBJsonParser new];
|
||||
id repr = [jsonParser objectWithString:self];
|
||||
if (!repr)
|
||||
//CCLOG(@"-JSONValue failed. Error trace is: %@", [jsonParser errorTrace]);
|
||||
[jsonParser release];
|
||||
return repr;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright (C) 2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SBJsonBase.h"
|
||||
|
||||
/**
|
||||
@brief Options for the writer class.
|
||||
|
||||
This exists so the SBJSON facade can implement the options in the writer without having to re-declare them.
|
||||
*/
|
||||
@protocol SBJsonWriter
|
||||
|
||||
/**
|
||||
@brief Whether we are generating human-readable (multiline) JSON.
|
||||
|
||||
Set whether or not to generate human-readable JSON. The default is NO, which produces
|
||||
JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable
|
||||
JSON with linebreaks after each array value and dictionary key/value pair, indented two
|
||||
spaces per nesting level.
|
||||
*/
|
||||
@property BOOL humanReadable;
|
||||
|
||||
/**
|
||||
@brief Whether or not to sort the dictionary keys in the output.
|
||||
|
||||
If this is set to YES, the dictionary keys in the JSON output will be in sorted order.
|
||||
(This is useful if you need to compare two structures, for example.) The default is NO.
|
||||
*/
|
||||
@property BOOL sortKeys;
|
||||
|
||||
/**
|
||||
@brief Return JSON representation (or fragment) for the given object.
|
||||
|
||||
Returns a string containing JSON representation of the passed in value, or nil on error.
|
||||
If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error.
|
||||
|
||||
@param value any instance that can be represented as a JSON fragment
|
||||
|
||||
*/
|
||||
- (NSString*)stringWithObject:(id)value;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
@brief The JSON writer class.
|
||||
|
||||
Objective-C types are mapped to JSON types in the following way:
|
||||
|
||||
@li NSNull -> Null
|
||||
@li NSString -> String
|
||||
@li NSArray -> Array
|
||||
@li NSDictionary -> Object
|
||||
@li NSNumber (-initWithBool:) -> Boolean
|
||||
@li NSNumber -> Number
|
||||
|
||||
In JSON the keys of an object must be strings. NSDictionary keys need
|
||||
not be, but attempting to convert an NSDictionary with non-string keys
|
||||
into JSON will throw an exception.
|
||||
|
||||
NSNumber instances created with the +initWithBool: method are
|
||||
converted into the JSON boolean "true" and "false" values, and vice
|
||||
versa. Any other NSNumber instances are converted to a JSON number the
|
||||
way you would expect.
|
||||
|
||||
*/
|
||||
@interface SBJsonWriter : SBJsonBase <SBJsonWriter> {
|
||||
|
||||
@private
|
||||
BOOL sortKeys, humanReadable;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// don't use - exists for backwards compatibility. Will be removed in 2.3.
|
||||
@interface SBJsonWriter (Private)
|
||||
- (NSString*)stringWithFragment:(id)value;
|
||||
@end
|
||||
|
||||
/**
|
||||
@brief Allows generation of JSON for otherwise unsupported classes.
|
||||
|
||||
If you have a custom class that you want to create a JSON representation for you can implement
|
||||
this method in your class. It should return a representation of your object defined
|
||||
in terms of objects that can be translated into JSON. For example, a Person
|
||||
object might implement it like this:
|
||||
|
||||
@code
|
||||
- (id)jsonProxyObject {
|
||||
return [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
phone, @"phone",
|
||||
email, @"email",
|
||||
nil];
|
||||
}
|
||||
@endcode
|
||||
|
||||
*/
|
||||
@interface NSObject (SBProxyForJson)
|
||||
- (id)proxyForJson;
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
Copyright (C) 2007-2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "SBJSON.h"
|
||||
|
||||
@implementation SBJSON
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
jsonWriter = [SBJsonWriter new];
|
||||
jsonParser = [SBJsonParser new];
|
||||
[self setMaxDepth:512];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[jsonWriter release];
|
||||
[jsonParser release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark Writer
|
||||
|
||||
|
||||
- (NSString *)stringWithObject:(id)obj {
|
||||
NSString *repr = [jsonWriter stringWithObject:obj];
|
||||
if (repr)
|
||||
return repr;
|
||||
|
||||
[errorTrace release];
|
||||
errorTrace = [[jsonWriter errorTrace] mutableCopy];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a string containing JSON representation of the passed in value, or nil on error.
|
||||
If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error.
|
||||
|
||||
@param value any instance that can be represented as a JSON fragment
|
||||
@param allowScalar wether to return json fragments for scalar objects
|
||||
@param error used to return an error by reference (pass NULL if this is not desired)
|
||||
|
||||
@deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
|
||||
*/
|
||||
- (NSString*)stringWithObject:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error {
|
||||
|
||||
NSString *json = allowScalar ? [jsonWriter stringWithFragment:value] : [jsonWriter stringWithObject:value];
|
||||
if (json)
|
||||
return json;
|
||||
|
||||
[errorTrace release];
|
||||
errorTrace = [[jsonWriter errorTrace] mutableCopy];
|
||||
|
||||
if (error)
|
||||
*error = [errorTrace lastObject];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a string containing JSON representation of the passed in value, or nil on error.
|
||||
If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error.
|
||||
|
||||
@param value any instance that can be represented as a JSON fragment
|
||||
@param error used to return an error by reference (pass NULL if this is not desired)
|
||||
|
||||
@deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
|
||||
*/
|
||||
- (NSString*)stringWithFragment:(id)value error:(NSError**)error {
|
||||
return [self stringWithObject:value
|
||||
allowScalar:YES
|
||||
error:error];
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a string containing JSON representation of the passed in value, or nil on error.
|
||||
If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error.
|
||||
|
||||
@param value a NSDictionary or NSArray instance
|
||||
@param error used to return an error by reference (pass NULL if this is not desired)
|
||||
*/
|
||||
- (NSString*)stringWithObject:(id)value error:(NSError**)error {
|
||||
return [self stringWithObject:value
|
||||
allowScalar:NO
|
||||
error:error];
|
||||
}
|
||||
|
||||
#pragma mark Parsing
|
||||
|
||||
- (id)objectWithString:(NSString *)repr {
|
||||
id obj = [jsonParser objectWithString:repr];
|
||||
if (obj)
|
||||
return obj;
|
||||
|
||||
[errorTrace release];
|
||||
errorTrace = [[jsonParser errorTrace] mutableCopy];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the object represented by the passed-in string or nil on error. The returned object can be
|
||||
a string, number, boolean, null, array or dictionary.
|
||||
|
||||
@param value the json string to parse
|
||||
@param allowScalar whether to return objects for JSON fragments
|
||||
@param error used to return an error by reference (pass NULL if this is not desired)
|
||||
|
||||
@deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
|
||||
*/
|
||||
- (id)objectWithString:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error {
|
||||
|
||||
id obj = allowScalar ? [jsonParser fragmentWithString:value] : [jsonParser objectWithString:value];
|
||||
if (obj)
|
||||
return obj;
|
||||
|
||||
[errorTrace release];
|
||||
errorTrace = [[jsonParser errorTrace] mutableCopy];
|
||||
|
||||
if (error)
|
||||
*error = [errorTrace lastObject];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the object represented by the passed-in string or nil on error. The returned object can be
|
||||
a string, number, boolean, null, array or dictionary.
|
||||
|
||||
@param repr the json string to parse
|
||||
@param error used to return an error by reference (pass NULL if this is not desired)
|
||||
|
||||
@deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
|
||||
*/
|
||||
- (id)fragmentWithString:(NSString*)repr error:(NSError**)error {
|
||||
return [self objectWithString:repr
|
||||
allowScalar:YES
|
||||
error:error];
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the object represented by the passed-in string or nil on error. The returned object
|
||||
will be either a dictionary or an array.
|
||||
|
||||
@param repr the json string to parse
|
||||
@param error used to return an error by reference (pass NULL if this is not desired)
|
||||
*/
|
||||
- (id)objectWithString:(NSString*)repr error:(NSError**)error {
|
||||
return [self objectWithString:repr
|
||||
allowScalar:NO
|
||||
error:error];
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark Properties - parsing
|
||||
|
||||
- (NSUInteger)maxDepth {
|
||||
return jsonParser.maxDepth;
|
||||
}
|
||||
|
||||
- (void)setMaxDepth:(NSUInteger)d {
|
||||
jsonWriter.maxDepth = jsonParser.maxDepth = d;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Properties - writing
|
||||
|
||||
- (BOOL)humanReadable {
|
||||
return jsonWriter.humanReadable;
|
||||
}
|
||||
|
||||
- (void)setHumanReadable:(BOOL)x {
|
||||
jsonWriter.humanReadable = x;
|
||||
}
|
||||
|
||||
- (BOOL)sortKeys {
|
||||
return jsonWriter.sortKeys;
|
||||
}
|
||||
|
||||
- (void)setSortKeys:(BOOL)x {
|
||||
jsonWriter.sortKeys = x;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright (C) 2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "NSObject+SBJSON.h"
|
||||
#import "SBJsonWriter.h"
|
||||
|
||||
@implementation NSObject (NSObject_SBJSON)
|
||||
|
||||
- (NSString *)JSONFragment {
|
||||
SBJsonWriter *jsonWriter = [SBJsonWriter new];
|
||||
NSString *json = [jsonWriter stringWithFragment:self];
|
||||
if (!json)
|
||||
// CCLOG(@"-JSONFragment failed. Error trace is: %@", [jsonWriter errorTrace]);
|
||||
[jsonWriter release];
|
||||
return json;
|
||||
}
|
||||
|
||||
- (NSString *)JSONRepresentation {
|
||||
SBJsonWriter *jsonWriter = [SBJsonWriter new];
|
||||
NSString *json = [jsonWriter stringWithObject:self];
|
||||
if (!json)
|
||||
// CCLOG(@"-JSONRepresentation failed. Error trace is: %@", [jsonWriter errorTrace]);
|
||||
[jsonWriter release];
|
||||
return json;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright (C) 2007-2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SBJsonParser.h"
|
||||
#import "SBJsonWriter.h"
|
||||
|
||||
/**
|
||||
@brief Facade for SBJsonWriter/SBJsonParser.
|
||||
|
||||
Requests are forwarded to instances of SBJsonWriter and SBJsonParser.
|
||||
*/
|
||||
@interface SBJSON : SBJsonBase <SBJsonParser, SBJsonWriter> {
|
||||
|
||||
@private
|
||||
SBJsonParser *jsonParser;
|
||||
SBJsonWriter *jsonWriter;
|
||||
}
|
||||
|
||||
|
||||
/// Return the fragment represented by the given string
|
||||
- (id)fragmentWithString:(NSString*)jsonrep
|
||||
error:(NSError**)error;
|
||||
|
||||
/// Return the object represented by the given string
|
||||
- (id)objectWithString:(NSString*)jsonrep
|
||||
error:(NSError**)error;
|
||||
|
||||
/// Parse the string and return the represented object (or scalar)
|
||||
- (id)objectWithString:(id)value
|
||||
allowScalar:(BOOL)x
|
||||
error:(NSError**)error;
|
||||
|
||||
|
||||
/// Return JSON representation of an array or dictionary
|
||||
- (NSString*)stringWithObject:(id)value
|
||||
error:(NSError**)error;
|
||||
|
||||
/// Return JSON representation of any legal JSON value
|
||||
- (NSString*)stringWithFragment:(id)value
|
||||
error:(NSError**)error;
|
||||
|
||||
/// Return JSON representation (or fragment) for the given object
|
||||
- (NSString*)stringWithObject:(id)value
|
||||
allowScalar:(BOOL)x
|
||||
error:(NSError**)error;
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
Copyright (C) 2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "SBJsonParser.h"
|
||||
|
||||
@interface SBJsonParser ()
|
||||
|
||||
- (BOOL)scanValue:(NSObject **)o;
|
||||
|
||||
- (BOOL)scanRestOfArray:(NSMutableArray **)o;
|
||||
- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o;
|
||||
- (BOOL)scanRestOfNull:(NSNull **)o;
|
||||
- (BOOL)scanRestOfFalse:(NSNumber **)o;
|
||||
- (BOOL)scanRestOfTrue:(NSNumber **)o;
|
||||
- (BOOL)scanRestOfString:(NSMutableString **)o;
|
||||
|
||||
// Cannot manage without looking at the first digit
|
||||
- (BOOL)scanNumber:(NSNumber **)o;
|
||||
|
||||
- (BOOL)scanHexQuad:(unichar *)x;
|
||||
- (BOOL)scanUnicodeChar:(unichar *)x;
|
||||
|
||||
- (BOOL)scanIsAtEnd;
|
||||
|
||||
@end
|
||||
|
||||
#define skipWhitespace(c) while (isspace(*c)) c++
|
||||
#define skipDigits(c) while (isdigit(*c)) c++
|
||||
|
||||
|
||||
@implementation SBJsonParser
|
||||
|
||||
static char ctrl[0x22];
|
||||
|
||||
|
||||
+ (void)initialize {
|
||||
ctrl[0] = '\"';
|
||||
ctrl[1] = '\\';
|
||||
for (int i = 1; i < 0x20; i++)
|
||||
ctrl[i+1] = i;
|
||||
ctrl[0x21] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@deprecated This exists in order to provide fragment support in older APIs in one more version.
|
||||
It should be removed in the next major version.
|
||||
*/
|
||||
- (id)fragmentWithString:(id)repr {
|
||||
[self clearErrorTrace];
|
||||
|
||||
if (!repr) {
|
||||
[self addErrorWithCode:EINPUT description:@"Input was 'nil'"];
|
||||
return nil;
|
||||
}
|
||||
|
||||
depth = 0;
|
||||
c = [repr UTF8String];
|
||||
|
||||
id o;
|
||||
if (![self scanValue:&o]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// We found some valid JSON. But did it also contain something else?
|
||||
if (![self scanIsAtEnd]) {
|
||||
[self addErrorWithCode:ETRAILGARBAGE description:@"Garbage after JSON"];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSAssert1(o, @"Should have a valid object from %@", repr);
|
||||
return o;
|
||||
}
|
||||
|
||||
- (id)objectWithString:(NSString *)repr {
|
||||
|
||||
id o = [self fragmentWithString:repr];
|
||||
if (!o)
|
||||
return nil;
|
||||
|
||||
// Check that the object we've found is a valid JSON container.
|
||||
if (![o isKindOfClass:[NSDictionary class]] && ![o isKindOfClass:[NSArray class]]) {
|
||||
[self addErrorWithCode:EFRAGMENT description:@"Valid fragment, but not JSON"];
|
||||
return nil;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/*
|
||||
In contrast to the public methods, it is an error to omit the error parameter here.
|
||||
*/
|
||||
- (BOOL)scanValue:(NSObject **)o
|
||||
{
|
||||
skipWhitespace(c);
|
||||
|
||||
switch (*c++) {
|
||||
case '{':
|
||||
return [self scanRestOfDictionary:(NSMutableDictionary **)o];
|
||||
break;
|
||||
case '[':
|
||||
return [self scanRestOfArray:(NSMutableArray **)o];
|
||||
break;
|
||||
case '"':
|
||||
return [self scanRestOfString:(NSMutableString **)o];
|
||||
break;
|
||||
case 'f':
|
||||
return [self scanRestOfFalse:(NSNumber **)o];
|
||||
break;
|
||||
case 't':
|
||||
return [self scanRestOfTrue:(NSNumber **)o];
|
||||
break;
|
||||
case 'n':
|
||||
return [self scanRestOfNull:(NSNull **)o];
|
||||
break;
|
||||
case '-':
|
||||
case '0'...'9':
|
||||
c--; // cannot verify number correctly without the first character
|
||||
return [self scanNumber:(NSNumber **)o];
|
||||
break;
|
||||
case '+':
|
||||
[self addErrorWithCode:EPARSENUM description: @"Leading + disallowed in number"];
|
||||
return NO;
|
||||
break;
|
||||
case 0x0:
|
||||
[self addErrorWithCode:EEOF description:@"Unexpected end of string"];
|
||||
return NO;
|
||||
break;
|
||||
default:
|
||||
[self addErrorWithCode:EPARSE description: @"Unrecognised leading character"];
|
||||
return NO;
|
||||
break;
|
||||
}
|
||||
|
||||
NSAssert(0, @"Should never get here");
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)scanRestOfTrue:(NSNumber **)o
|
||||
{
|
||||
if (!strncmp(c, "rue", 3)) {
|
||||
c += 3;
|
||||
*o = [NSNumber numberWithBool:YES];
|
||||
return YES;
|
||||
}
|
||||
[self addErrorWithCode:EPARSE description:@"Expected 'true'"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)scanRestOfFalse:(NSNumber **)o
|
||||
{
|
||||
if (!strncmp(c, "alse", 4)) {
|
||||
c += 4;
|
||||
*o = [NSNumber numberWithBool:NO];
|
||||
return YES;
|
||||
}
|
||||
[self addErrorWithCode:EPARSE description: @"Expected 'false'"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)scanRestOfNull:(NSNull **)o {
|
||||
if (!strncmp(c, "ull", 3)) {
|
||||
c += 3;
|
||||
*o = [NSNull null];
|
||||
return YES;
|
||||
}
|
||||
[self addErrorWithCode:EPARSE description: @"Expected 'null'"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)scanRestOfArray:(NSMutableArray **)o {
|
||||
if (maxDepth && ++depth > maxDepth) {
|
||||
[self addErrorWithCode:EDEPTH description: @"Nested too deep"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
*o = [NSMutableArray arrayWithCapacity:8];
|
||||
|
||||
for (; *c ;) {
|
||||
id v;
|
||||
|
||||
skipWhitespace(c);
|
||||
if (*c == ']' && c++) {
|
||||
depth--;
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (![self scanValue:&v]) {
|
||||
[self addErrorWithCode:EPARSE description:@"Expected value while parsing array"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
[*o addObject:v];
|
||||
|
||||
skipWhitespace(c);
|
||||
if (*c == ',' && c++) {
|
||||
skipWhitespace(c);
|
||||
if (*c == ']') {
|
||||
[self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in array"];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self addErrorWithCode:EEOF description: @"End of input while parsing array"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o
|
||||
{
|
||||
if (maxDepth && ++depth > maxDepth) {
|
||||
[self addErrorWithCode:EDEPTH description: @"Nested too deep"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
*o = [NSMutableDictionary dictionaryWithCapacity:7];
|
||||
|
||||
for (; *c ;) {
|
||||
id k, v;
|
||||
|
||||
skipWhitespace(c);
|
||||
if (*c == '}' && c++) {
|
||||
depth--;
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (!(*c == '\"' && c++ && [self scanRestOfString:&k])) {
|
||||
[self addErrorWithCode:EPARSE description: @"Object key string expected"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
skipWhitespace(c);
|
||||
if (*c != ':') {
|
||||
[self addErrorWithCode:EPARSE description: @"Expected ':' separating key and value"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
c++;
|
||||
if (![self scanValue:&v]) {
|
||||
NSString *string = [NSString stringWithFormat:@"Object value expected for key: %@", k];
|
||||
[self addErrorWithCode:EPARSE description: string];
|
||||
return NO;
|
||||
}
|
||||
|
||||
[*o setObject:v forKey:k];
|
||||
|
||||
skipWhitespace(c);
|
||||
if (*c == ',' && c++) {
|
||||
skipWhitespace(c);
|
||||
if (*c == '}') {
|
||||
[self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in object"];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self addErrorWithCode:EEOF description: @"End of input while parsing object"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)scanRestOfString:(NSMutableString **)o
|
||||
{
|
||||
*o = [NSMutableString stringWithCapacity:16];
|
||||
do {
|
||||
// First see if there's a portion we can grab in one go.
|
||||
// Doing this caused a massive speedup on the long string.
|
||||
size_t len = strcspn(c, ctrl);
|
||||
if (len) {
|
||||
// check for
|
||||
id t = [[NSString alloc] initWithBytesNoCopy:(char*)c
|
||||
length:len
|
||||
encoding:NSUTF8StringEncoding
|
||||
freeWhenDone:NO];
|
||||
if (t) {
|
||||
[*o appendString:t];
|
||||
[t release];
|
||||
c += len;
|
||||
}
|
||||
}
|
||||
|
||||
if (*c == '"') {
|
||||
c++;
|
||||
return YES;
|
||||
|
||||
} else if (*c == '\\') {
|
||||
unichar uc = *++c;
|
||||
switch (uc) {
|
||||
case '\\':
|
||||
case '/':
|
||||
case '"':
|
||||
break;
|
||||
|
||||
case 'b': uc = '\b'; break;
|
||||
case 'n': uc = '\n'; break;
|
||||
case 'r': uc = '\r'; break;
|
||||
case 't': uc = '\t'; break;
|
||||
case 'f': uc = '\f'; break;
|
||||
|
||||
case 'u':
|
||||
c++;
|
||||
if (![self scanUnicodeChar:&uc]) {
|
||||
[self addErrorWithCode:EUNICODE description: @"Broken unicode character"];
|
||||
return NO;
|
||||
}
|
||||
c--; // hack.
|
||||
break;
|
||||
default:
|
||||
[self addErrorWithCode:EESCAPE description: [NSString stringWithFormat:@"Illegal escape sequence '0x%x'", uc]];
|
||||
return NO;
|
||||
break;
|
||||
}
|
||||
CFStringAppendCharacters((CFMutableStringRef)*o, &uc, 1);
|
||||
c++;
|
||||
|
||||
} else if (*c < 0x20) {
|
||||
[self addErrorWithCode:ECTRL description: [NSString stringWithFormat:@"Unescaped control character '0x%x'", *c]];
|
||||
return NO;
|
||||
|
||||
} else {
|
||||
// CCLOG(@"should not be able to get here");
|
||||
}
|
||||
} while (*c);
|
||||
|
||||
[self addErrorWithCode:EEOF description:@"Unexpected EOF while parsing string"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)scanUnicodeChar:(unichar *)x
|
||||
{
|
||||
unichar hi, lo;
|
||||
|
||||
if (![self scanHexQuad:&hi]) {
|
||||
[self addErrorWithCode:EUNICODE description: @"Missing hex quad"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (hi >= 0xd800) { // high surrogate char?
|
||||
if (hi < 0xdc00) { // yes - expect a low char
|
||||
|
||||
if (!(*c == '\\' && ++c && *c == 'u' && ++c && [self scanHexQuad:&lo])) {
|
||||
[self addErrorWithCode:EUNICODE description: @"Missing low character in surrogate pair"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (lo < 0xdc00 || lo >= 0xdfff) {
|
||||
[self addErrorWithCode:EUNICODE description:@"Invalid low surrogate char"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
hi = (hi - 0xd800) * 0x400 + (lo - 0xdc00) + 0x10000;
|
||||
|
||||
} else if (hi < 0xe000) {
|
||||
[self addErrorWithCode:EUNICODE description:@"Invalid high character in surrogate pair"];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
*x = hi;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)scanHexQuad:(unichar *)x
|
||||
{
|
||||
*x = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
unichar uc = *c;
|
||||
c++;
|
||||
int d = (uc >= '0' && uc <= '9')
|
||||
? uc - '0' : (uc >= 'a' && uc <= 'f')
|
||||
? (uc - 'a' + 10) : (uc >= 'A' && uc <= 'F')
|
||||
? (uc - 'A' + 10) : -1;
|
||||
if (d == -1) {
|
||||
[self addErrorWithCode:EUNICODE description:@"Missing hex digit in quad"];
|
||||
return NO;
|
||||
}
|
||||
*x *= 16;
|
||||
*x += d;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)scanNumber:(NSNumber **)o
|
||||
{
|
||||
const char *ns = c;
|
||||
|
||||
// The logic to test for validity of the number formatting is relicensed
|
||||
// from JSON::XS with permission from its author Marc Lehmann.
|
||||
// (Available at the CPAN: http://search.cpan.org/dist/JSON-XS/ .)
|
||||
|
||||
if ('-' == *c)
|
||||
c++;
|
||||
|
||||
if ('0' == *c && c++) {
|
||||
if (isdigit(*c)) {
|
||||
[self addErrorWithCode:EPARSENUM description: @"Leading 0 disallowed in number"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
} else if (!isdigit(*c) && c != ns) {
|
||||
[self addErrorWithCode:EPARSENUM description: @"No digits after initial minus"];
|
||||
return NO;
|
||||
|
||||
} else {
|
||||
skipDigits(c);
|
||||
}
|
||||
|
||||
// Fractional part
|
||||
if ('.' == *c && c++) {
|
||||
|
||||
if (!isdigit(*c)) {
|
||||
[self addErrorWithCode:EPARSENUM description: @"No digits after decimal point"];
|
||||
return NO;
|
||||
}
|
||||
skipDigits(c);
|
||||
}
|
||||
|
||||
// Exponential part
|
||||
if ('e' == *c || 'E' == *c) {
|
||||
c++;
|
||||
|
||||
if ('-' == *c || '+' == *c)
|
||||
c++;
|
||||
|
||||
if (!isdigit(*c)) {
|
||||
[self addErrorWithCode:EPARSENUM description: @"No digits after exponent"];
|
||||
return NO;
|
||||
}
|
||||
skipDigits(c);
|
||||
}
|
||||
|
||||
id str = [[NSString alloc] initWithBytesNoCopy:(char*)ns
|
||||
length:c - ns
|
||||
encoding:NSUTF8StringEncoding
|
||||
freeWhenDone:NO];
|
||||
[str autorelease];
|
||||
if (str && (*o = [NSDecimalNumber decimalNumberWithString:str]))
|
||||
return YES;
|
||||
|
||||
[self addErrorWithCode:EPARSENUM description: @"Failed creating decimal instance"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)scanIsAtEnd
|
||||
{
|
||||
skipWhitespace(c);
|
||||
return !*c;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Copyright (C) 2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@mainpage A strict JSON parser and generator for Objective-C
|
||||
|
||||
JSON (JavaScript Object Notation) is a lightweight data-interchange
|
||||
format. This framework provides two apis for parsing and generating
|
||||
JSON. One standard object-based and a higher level api consisting of
|
||||
categories added to existing Objective-C classes.
|
||||
|
||||
Learn more on the http://code.google.com/p/json-framework project site.
|
||||
|
||||
This framework does its best to be as strict as possible, both in what it
|
||||
accepts and what it generates. For example, it does not support trailing commas
|
||||
in arrays or objects. Nor does it support embedded comments, or
|
||||
anything else not in the JSON specification. This is considered a feature.
|
||||
|
||||
*/
|
||||
|
||||
#import "SBJSON.h"
|
||||
#import "NSObject+SBJSON.h"
|
||||
#import "NSString+SBJSON.h"
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright (C) 2009 Stig Brautaset. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
/**
|
||||
@brief Adds JSON generation to Foundation classes
|
||||
|
||||
This is a category on NSObject that adds methods for returning JSON representations
|
||||
of standard objects to the objects themselves. This means you can call the
|
||||
-JSONRepresentation method on an NSArray object and it'll do what you want.
|
||||
*/
|
||||
@interface NSObject (NSObject_SBJSON)
|
||||
|
||||
/**
|
||||
@brief Returns a string containing the receiver encoded as a JSON fragment.
|
||||
|
||||
This method is added as a category on NSObject but is only actually
|
||||
supported for the following objects:
|
||||
@li NSDictionary
|
||||
@li NSArray
|
||||
@li NSString
|
||||
@li NSNumber (also used for booleans)
|
||||
@li NSNull
|
||||
|
||||
@deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed.
|
||||
*/
|
||||
- (NSString *)JSONFragment;
|
||||
|
||||
/**
|
||||
@brief Returns a string containing the receiver encoded in JSON.
|
||||
|
||||
This method is added as a category on NSObject but is only actually
|
||||
supported for the following objects:
|
||||
@li NSDictionary
|
||||
@li NSArray
|
||||
*/
|
||||
- (NSString *)JSONRepresentation;
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user