Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -64,10 +64,11 @@ of_strptime.m \ unicode.m INCLUDES := ${SRCS:.m=.h} \ OFCollection.h \ + OFJSON.h \ OFSerialization.h \ ObjFW.h \ asprintf.h \ ${ATOMIC_H} \ macros.h \ Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -18,10 +18,11 @@ #import "OFObject.h" #import "OFCollection.h" #import "OFEnumerator.h" #import "OFSerialization.h" +#import "OFJSON.h" @class OFString; #ifdef OF_HAVE_BLOCKS typedef void (^of_array_enumeration_block_t)(id object, size_t index, @@ -33,11 +34,11 @@ /** * \brief An abstract class for storing objects in an array. */ @interface OFArray: OFObject + OFSerialization, OFJSON> /** * \brief Creates a new OFArray. * * \return A new autoreleased OFArray */ @@ -230,10 +231,21 @@ * \param separator The string with which the objects should be joined * \return A string containing all objects joined by the separator */ - (OFString*)componentsJoinedByString: (OFString*)separator; +/** + * \brief Creates a string by calling the selector on all objects of the array + * and joining the strings returned by calling the selector. + * + * \param separator The string with which the objects should be joined + * \param selector The selector to perform on the objects + * \return A string containing all objects joined by the separator + */ +- (OFString*)componentsJoinedByString: (OFString*)separator + usingSelector: (SEL)selector; + /** * \brief Performs the specified selector on all objects in the array. * * \param selector The selector to perform on all objects in the array */ Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -363,10 +363,17 @@ return ret; } - (OFString*)componentsJoinedByString: (OFString*)separator +{ + return [self componentsJoinedByString: separator + usingSelector: @selector(description)]; +} + +- (OFString*)componentsJoinedByString: (OFString*)separator + usingSelector: (SEL)selector { OFAutoreleasePool *pool, *pool2; OFMutableString *ret; id *cArray; size_t i, count = [self count]; @@ -373,11 +380,11 @@ IMP append; if (count == 0) return @""; if (count == 1) - return [[self firstObject] description]; + return [[self firstObject] performSelector: selector]; ret = [OFMutableString string]; append = [ret methodForSelector: @selector(appendString:)]; pool = [[OFAutoreleasePool alloc] init]; @@ -384,16 +391,18 @@ cArray = [self cArray]; pool2 = [[OFAutoreleasePool alloc] init]; for (i = 0; i < count - 1; i++) { - append(ret, @selector(appendString:), [cArray[i] description]); + append(ret, @selector(appendString:), + [cArray[i] performSelector: selector]); append(ret, @selector(appendString:), separator); [pool2 releaseObjects]; } - append(ret, @selector(appendString:), [cArray[i] description]); + append(ret, @selector(appendString:), + [cArray[i] performSelector: selector]); [ret makeImmutable]; [pool release]; @@ -502,10 +511,29 @@ [pool release]; [element autorelease]; return element; } + +- (OFString*)JSONRepresentation +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFMutableString *JSON; + + JSON = [[self componentsJoinedByString: @"," + usingSelector: @selector(JSONRepresentation)] + mutableCopy]; + [pool release]; + [JSON autorelease]; + + [JSON prependString: @"["]; + [JSON appendString: @"]"]; + + [JSON makeImmutable]; + + return JSON; +} - (void)makeObjectsPerformSelector: (SEL)selector { id *cArray = [self cArray]; size_t i, count = [self count]; Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -18,10 +18,11 @@ #import "OFObject.h" #import "OFCollection.h" #import "OFEnumerator.h" #import "OFSerialization.h" +#import "OFJSON.h" @class OFArray; #ifdef OF_HAVE_BLOCKS typedef void (^of_dictionary_enumeration_block_t)(id key, id object, @@ -37,11 +38,11 @@ * * Note: Fast enumeration on a dictionary enumerates through the keys of the * dictionary. */ @interface OFDictionary: OFObject + OFSerialization, OFJSON> /** * \brief Creates a new OFDictionary. * * \return A new autoreleased OFDictionary */ Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -540,6 +540,38 @@ [pool release]; [element autorelease]; return element; } + +- (OFString*)JSONRepresentation +{ + OFMutableString *JSON = [OFMutableString stringWithString: @"{"]; + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init], *pool2; + OFEnumerator *keyEnumerator = [self keyEnumerator]; + OFEnumerator *objectEnumerator = [self objectEnumerator]; + size_t i = 0, count = [self count]; + OFString *key; + OFString *object; + + pool2 = [[OFAutoreleasePool alloc] init]; + + while ((key = [keyEnumerator nextObject]) != nil && + (object = [objectEnumerator nextObject]) != nil) { + [JSON appendString: [key JSONRepresentation]]; + [JSON appendString: @":"]; + [JSON appendString: [object JSONRepresentation]]; + + if (++i < count) + [JSON appendString: @","]; + + [pool2 releaseObjects]; + } + + [pool release]; + + [JSON appendString: @"}"]; + [JSON makeImmutable]; + + return JSON; +} @end ADDED src/OFJSON.h Index: src/OFJSON.h ================================================================== --- src/OFJSON.h +++ src/OFJSON.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +@class OFString; + +/** + * \brief A category implemented by classes that support a JSON representation. + */ +@protocol OFJSON +/** + * \brief Returns the JSON representation of the object as a string. + * + * \return The JSON representation of the object as a string. + */ +- (OFString*)JSONRepresentation; +@end Index: src/OFNull.h ================================================================== --- src/OFNull.h +++ src/OFNull.h @@ -14,17 +14,18 @@ * file. */ #import "OFObject.h" #import "OFSerialization.h" +#import "OFJSON.h" /** * \brief A class for representing null values in collections. */ -@interface OFNull: OFObject +@interface OFNull: OFObject /** * \brief Returns an OFNull singleton. * * \return An OFNull singleton */ + null; @end Index: src/OFNull.m ================================================================== --- src/OFNull.m +++ src/OFNull.m @@ -77,10 +77,15 @@ [pool release]; [element autorelease]; return element; } + +- (OFString*)JSONRepresentation +{ + return @"null"; +} - autorelease { return self; } Index: src/OFNumber.h ================================================================== --- src/OFNumber.h +++ src/OFNumber.h @@ -16,10 +16,11 @@ #include #import "OFObject.h" #import "OFSerialization.h" +#import "OFJSON.h" /** * \brief The type of a number. */ typedef enum of_number_type_t { @@ -52,11 +53,11 @@ } of_number_type_t; /** * \brief Provides a way to store a number in an object. */ -@interface OFNumber: OFObject +@interface OFNumber: OFObject { union of_number_value { BOOL bool_; signed char char_; signed short short_; Index: src/OFNumber.m ================================================================== --- src/OFNumber.m +++ src/OFNumber.m @@ -1239,6 +1239,14 @@ [pool release]; [element autorelease]; return element; } + +- (OFString*)JSONRepresentation +{ + if (type == OF_NUMBER_BOOL) + return (value.bool_ ? @"true" : @"false"); + + return [self description]; +} @end Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -18,10 +18,11 @@ #include #include #import "OFObject.h" #import "OFSerialization.h" +#import "OFJSON.h" #import "macros.h" @class OFConstantString; @@ -71,11 +72,11 @@ * for a constant string and get initialized on the first message! Therefore, * you should use the corresponding methods to get the ivars, which ensures the * constant string is initialized. */ @interface OFString: OFObject + OFSerialization, OFJSON> #ifdef OF_HAVE_PROPERTIES @property (readonly) size_t length; #endif /** Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -1135,10 +1135,38 @@ [pool release]; [element autorelease]; return element; } + +- (OFString*)JSONRepresentation +{ + OFMutableString *JSON = [[self mutableCopy] autorelease]; + + /* FIXME: This is slow! Write it in pure C! */ + [JSON replaceOccurrencesOfString: @"\\" + withString: @"\\\\"]; + [JSON replaceOccurrencesOfString: @"\"" + withString: @"\\\""]; + [JSON replaceOccurrencesOfString: @"\b" + withString: @"\\b"]; + [JSON replaceOccurrencesOfString: @"\f" + withString: @"\\f"]; + [JSON replaceOccurrencesOfString: @"\n" + withString: @"\\n"]; + [JSON replaceOccurrencesOfString: @"\r" + withString: @"\\r"]; + [JSON replaceOccurrencesOfString: @"\t" + withString: @"\\t"]; + + [JSON prependString: @"\""]; + [JSON appendString: @"\""]; + + [JSON makeImmutable]; + + return JSON; +} - (size_t)indexOfFirstOccurrenceOfString: (OFString*)string { OFAutoreleasePool *pool; const of_unichar_t *unicodeString, *searchString;