30@implementation NSString (OldSchoolPropertyListWriting)
32- (NSString *)oldSchoolPListFormatWithIndentation:(
unsigned)inIndentation errorDescription:(NSString **)outErrorDescription
34 NSCharacterSet *charSet;
35 NSRange foundRange, searchRange;
36 NSString *foundString;
37 NSMutableString *newString;
40 length = [
self length];
42 && [
self rangeOfCharacterFromSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]].location == NSNotFound
43 && ![[NSCharacterSet decimalDigitCharacterSet] longCharacterIsMember:[
self characterAtIndex:0]])
46 return [[
self copy] autorelease];
50 charSet = [NSCharacterSet characterSetWithCharactersInString:@"\"\r\n\\"];
51 foundRange = [
self rangeOfCharacterFromSet:charSet options:NSLiteralSearch];
52 if (NSNotFound == foundRange.location)
54 newString = (NSMutableString *)
self;
59 newString = [[[
self substringToIndex:foundRange.location] mutableCopy] autorelease];
64 foundString = [
self substringWithRange:foundRange];
65 if ([foundString isEqual:
@"\""]) [newString appendString:@"\\\
""];
66 else if ([foundString isEqual:
@"\n"]) [newString appendString:
@"\\\n"];
67 else if ([foundString isEqual:
@"\r"]) [newString appendString:
@"\\\r"];
68 else if ([foundString isEqual:
@"\\"]) [newString appendString:
@"\\\\"];
71 [NSException raise:NSInternalInconsistencyException format:@"%s: expected \" or newline, found %@", __PRETTY_FUNCTION__, foundString];
75 searchRange.location = foundRange.location + foundRange.length;
76 searchRange.length = length - searchRange.location;
79 foundRange = [
self rangeOfCharacterFromSet:charSet options:NSLiteralSearch range:searchRange];
80 if (NSNotFound == foundRange.location)
82 [newString appendString:[self substringWithRange:searchRange]];
88 return [NSString stringWithFormat:@"\"%@\"", newString];
95@implementation NSNumber (OldSchoolPropertyListWriting)
97- (NSString *)oldSchoolPListFormatWithIndentation:(
unsigned)inIndentation errorDescription:(NSString **)outErrorDescription
102 if ([
self oo_isBoolean])
104 if ([
self boolValue]) result =
@"true";
105 else result =
@"false";
107 else if ([
self oo_isFloatingPointNumber])
109 dVal = [
self doubleValue];
110 result = [NSString stringWithFormat:@"%.8g", dVal];
112 else result = [NSString stringWithFormat:@"%@", self];
116 if ([result isEqual:
@"inf"] || [result isEqual:
@"-inf"])
118 *outErrorDescription =
@"infinities cannot be represented in old-school property lists";
129@implementation NSData (OldSchoolPropertyListWriting)
131- (NSString *)oldSchoolPListFormatWithIndentation:(
unsigned)inIndentation errorDescription:(NSString **)outErrorDescription
133 const uint8_t *srcBytes;
134 uint8_t *dstBytes, *curr;
135 NSUInteger i, j, srcLength, dstLength;
136 const char hexTable[] =
"0123456789ABCDEF";
139 srcBytes = [
self bytes];
140 srcLength = [
self length];
142 dstLength = 2 * srcLength + srcLength/8 + 2 + (srcLength/64 * (1 + inIndentation));
144 dstBytes = malloc(dstLength);
145 if (dstBytes == NULL)
147 if (NULL != outErrorDescription)
149 *outErrorDescription = [NSString stringWithFormat:@"failed to allocate space (%lu bytes) for conversion of NSData to old-school property list representation", dstLength];
156 for (i = 0; i != srcLength; ++i)
158 if (0 != i && 0 == (i & 3))
164 while (--j) *curr++ = '\t';
168 *curr++ = hexTable[srcBytes[i] >> 4];
169 *curr++ = hexTable[srcBytes[i] & 0xF];
173 assert((
size_t)(curr - dstBytes) <= dstLength);
175 result = [[NSString alloc] initWithBytesNoCopy:dstBytes length:dstLength encoding:NSASCIIStringEncoding freeWhenDone:YES];
176 return [result autorelease];
182@implementation NSArray (OldSchoolPropertyListWriting)
184- (NSString *)oldSchoolPListFormatWithIndentation:(
unsigned)inIndentation errorDescription:(NSString **)outErrorDescription
186 NSMutableString *result;
190 result = [NSMutableString string];
192 [result appendString:@"("];
194 count = [
self count];
197 for (i = 0; i !=
count; ++i)
201 [result appendString:@","];
205 object = [
self objectAtIndex:i];
206 if (![
object conformsToProtocol:
@protocol (OldSchoolPropertyListWriting)])
208 if (
nil !=
object && NULL != outErrorDescription)
210 *outErrorDescription = [NSString stringWithFormat:@"non-plist object in dictionary"];
215 object = [object oldSchoolPListFormatWithIndentation:inIndentation + 1 errorDescription:outErrorDescription];
216 if (
nil ==
object)
return nil;
217 [result appendString:object];
221 [result appendString:@")"];
228@implementation NSDictionary (OldSchoolPropertyListWriting)
230- (NSString *)oldSchoolPListFormatWithIndentation:(
unsigned)inIndentation errorDescription:(NSString **)outErrorDescription
232 NSMutableString *result;
238 result = [NSMutableString string];
239 allKeys = [[
self allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
240 count = [allKeys count];
242 [result appendString:@"{"];
246 for (i = 0; i !=
count; ++i)
253 key = [allKeys objectAtIndex:i];
254 if (![key isKindOfClass:[NSString
class]])
256 if (NULL != outErrorDescription) *outErrorDescription = [NSString stringWithFormat:@"non-string key in dictionary"];
259 value = [
self objectForKey:key];
260 if (![value conformsToProtocol:
@protocol(OldSchoolPropertyListWriting)])
262 if (
nil != value && NULL != outErrorDescription)
264 *outErrorDescription = [NSString stringWithFormat:@"non-plist object in dictionary"];
269 key = [key oldSchoolPListFormatWithIndentation:inIndentation + 1 errorDescription:outErrorDescription];
270 if (
nil == key)
return nil;
271 valueDesc = [value oldSchoolPListFormatWithIndentation:inIndentation + 1 errorDescription:outErrorDescription];
272 if (
nil == valueDesc)
return nil;
274 [result appendFormat:@"%@ =", key];
275 if ([value isKindOfClass:[NSArray
class]] || [value isKindOfClass:[NSDictionary
class]])
281 [result appendString:@" "];
283 [result appendFormat:@"%@;", valueDesc];
287 [result appendString:@"}"];
295@interface NSObject (OldSchoolPropertyListWriting_Private)
297- (NSString *)oldSchoolPListFormatWithIndentation:(
unsigned)inIndentation errorDescription:(NSString **)outErrorDescription;
302@implementation NSObject (OldSchoolPropertyListWriting)
304- (NSData *)oldSchoolPListFormatWithErrorDescription:(NSString **)outErrorDescription
308 string = [
self oldSchoolPListFormatWithIndentation:0 errorDescription:outErrorDescription];
309 return [[string stringByAppendingString:@"\n"] dataUsingEncoding:NSUTF8StringEncoding];
313- (NSString *)oldSchoolPListFormatWithIndentation:(
unsigned)inIndentation errorDescription:(NSString **)outErrorDescription
315 if (NULL != outErrorDescription)
317 *outErrorDescription = [NSString stringWithFormat:@"Class %@ does not support OldSchoolPropertyListWriting", [
self className]];
327 [ioString appendString:@"\n"];
328 while (indentDepth--) [ioString appendString:@"\t"];
static void AppendNewLineAndIndent(NSMutableString *ioString, unsigned indentDepth)