Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -615,15 +615,20 @@ i = 0; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) { void *pool2 = objc_autoreleasePoolPush(); + int identifierOptions = + options | OF_JSON_REPRESENTATION_IDENTIFIER; + + if (![key isKindOfClass: [OFString class]]) + @throw [OFInvalidArgumentException exception]; [JSON appendString: indentation]; [JSON appendString: @"\t"]; [JSON appendString: [key - OF_JSONRepresentationWithOptions: options + OF_JSONRepresentationWithOptions: identifierOptions depth: depth + 1]]; [JSON appendString: @": "]; [JSON appendString: [object OF_JSONRepresentationWithOptions: options depth: depth + 1]]; @@ -640,13 +645,18 @@ } else { i = 0; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) { void *pool2 = objc_autoreleasePoolPush(); + int identifierOptions = + options | OF_JSON_REPRESENTATION_IDENTIFIER; + + if (![key isKindOfClass: [OFString class]]) + @throw [OFInvalidArgumentException exception]; [JSON appendString: [key - OF_JSONRepresentationWithOptions: options + OF_JSONRepresentationWithOptions: identifierOptions depth: depth + 1]]; [JSON appendString: @":"]; [JSON appendString: [object OF_JSONRepresentationWithOptions: options depth: depth + 1]]; Index: src/OFJSONRepresentation.h ================================================================== --- src/OFJSONRepresentation.h +++ src/OFJSONRepresentation.h @@ -15,11 +15,13 @@ */ @class OFString; enum { - OF_JSON_REPRESENTATION_PRETTY = 1 + OF_JSON_REPRESENTATION_PRETTY = 0x01, + OF_JSON_REPRESENTATION_JSON5 = 0x02, + OF_JSON_REPRESENTATION_IDENTIFIER = 0x10 }; /*! * @brief A protocol implemented by classes that support encoding to a JSON * representation. @@ -42,10 +44,11 @@ * @param options The options to use when creating a JSON representation.@n * Possible values are: * Value | Description * --------------------------------|------------------------- * `OF_JSON_REPRESENTATION_PRETTY` | Optimize for readability + * `OF_JSON_REPRESENTATION_JSON5` | Generate JSON5 * * @return The JSON representation of the object as a string */ - (OFString*)JSONRepresentationWithOptions: (int)options; @end Index: src/OFNumber.m ================================================================== --- src/OFNumber.m +++ src/OFNumber.m @@ -1422,14 +1422,17 @@ if (_type == OF_NUMBER_BOOL) return (_value.bool_ ? @"true" : @"false"); doubleValue = [self doubleValue]; if (isinf(doubleValue)) { - if (doubleValue > 0) - return @"Infinity"; - else - return @"-Infinity"; + if (options & OF_JSON_REPRESENTATION_JSON5) { + if (doubleValue > 0) + return @"Infinity"; + else + return @"-Infinity"; + } else + @throw [OFInvalidArgumentException exception]; } return [self description]; } Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -17,10 +17,11 @@ #include "config.h" #include #include #include +#include #include #import "OFString.h" #import "OFString_UTF8.h" @@ -1458,19 +1459,39 @@ 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: @"\""]; + if (options & OF_JSON_REPRESENTATION_JSON5) { + [JSON replaceOccurrencesOfString: @"\n" + withString: @"\\\n"]; + + if (options & OF_JSON_REPRESENTATION_IDENTIFIER) { + const char *cString = [self UTF8String]; + + if ((!isalpha(cString[0]) && cString[0] != '_' && + cString[0] != '$') || + strpbrk(cString, " \n\r\t\b\f\\\"'") != NULL) { + [JSON prependString: @"\""]; + [JSON appendString: @"\""]; + } + } else { + [JSON prependString: @"\""]; + [JSON appendString: @"\""]; + } + } else { + [JSON replaceOccurrencesOfString: @"\n" + withString: @"\\n"]; + + [JSON prependString: @"\""]; + [JSON appendString: @"\""]; + } [JSON makeImmutable]; return JSON; }