diff --git a/ChangeLog b/ChangeLog index 85ea28392..cfdf17b27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-09-10 Richard Frith-Macdonald + + * Source/NSJSONSerialization.m: + Fix quoting of string output by copying code from WebServices library. + 2012-09-10 Richard Frith-Macdonald * Source/NSJSONSerialization.m: diff --git a/Source/NSJSONSerialization.m b/Source/NSJSONSerialization.m index 0500b4e62..2bdab5a06 100644 --- a/Source/NSJSONSerialization.m +++ b/Source/NSJSONSerialization.m @@ -788,38 +788,87 @@ writeObject(id obj, NSMutableString *output, NSInteger tabs) } else if ([obj isKindOfClass: NSStringClass]) { - NSRange r = [obj rangeOfCharacterFromSet: escapeSet]; - if (r.location != NSNotFound) - { - NSMutableString *str = [obj mutableCopy]; - NSCharacterSet *controlSet = [NSCharacterSet controlCharacterSet]; - [str replaceOccurrencesOfString: @"\\" - withString: @"\\\\" - options: 0 - range: NSMakeRange(0, [str length])]; - [str replaceOccurrencesOfString: @"\"" - withString: @"\\\"" - options: 0 - range: NSMakeRange(0, [str length])]; - r = [str rangeOfCharacterFromSet: controlSet]; - while (r.location != NSNotFound) - { - unichar control = [str characterAtIndex: r.location]; - NSString *escaped; + NSString *str = (NSString*)obj; + unsigned length = [str length]; - escaped = [[NSString alloc] initWithFormat: @"\\u%.4d", - (int)control]; - [str replaceCharactersInRange: r - withString: escaped]; - [escaped release]; - r = [str rangeOfCharacterFromSet: controlSet]; - } - [output appendFormat: @"\"%@\"", str]; - [str release]; + if (length == 0) + { + [output appendString: @"\"\""]; } else { - [output appendFormat: @"\"%@\"", obj]; + unsigned size = 2; + unichar *from; + unsigned i = 0; + unichar *to; + unsigned j = 0; + + from = NSZoneMalloc (NSDefaultMallocZone(), sizeof(unichar) * length); + [str getCharacters: from]; + + for (i = 0; i < length; i++) + { + unichar c = from[i]; + + if (c == '"' || c == '\\' || c == '\b' + || c == '\f' || c == '\n' || c == '\r' || c == '\t') + { + size += 2; + } + else if (c < 0x20) + { + size += 6; + } + else + { + size++; + } + } + + to = NSZoneMalloc (NSDefaultMallocZone(), sizeof(unichar) * size); + to[j++] = '"'; + for (i = 0; i < length; i++) + { + unichar c = from[i]; + + if (c == '"' || c == '\\' || c == '\b' + || c == '\f' || c == '\n' || c == '\r' || c == '\t') + { + to[j++] = '\\'; + switch (c) + { + case '\\': to[j++] = '\\'; break; + case '\b': to[j++] = 'b'; break; + case '\f': to[j++] = 'f'; break; + case '\n': to[j++] = 'n'; break; + case '\r': to[j++] = 'r'; break; + case '\t': to[j++] = 't'; break; + default: to[j++] = '"'; break; + } + } + else if (c < 0x20) + { + char buf[5]; + + to[j++] = '\\'; + to[j++] = 'u'; + sprintf(buf, "%04x", c); + to[j++] = buf[0]; + to[j++] = buf[1]; + to[j++] = buf[2]; + to[j++] = buf[3]; + } + else + { + to[j++] = c; + } + } + to[j] = '"'; + str = [[NSStringClass alloc] initWithCharacters: to length: size]; + NSZoneFree (NSDefaultMallocZone (), to); + NSZoneFree (NSDefaultMallocZone (), from); + [output appendString: str]; + [str release]; } } else if (obj == boolN)