Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -228,10 +228,11 @@ 4B90B7A3133AD87D00BD33CB /* OFBindFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90B799133AD87D00BD33CB /* OFBindFailedException.m */; }; 4B90B7A4133AD87D00BD33CB /* OFConnectionFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B90B79A133AD87D00BD33CB /* OFConnectionFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B90B7A5133AD87D00BD33CB /* OFConnectionFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90B79B133AD87D00BD33CB /* OFConnectionFailedException.m */; }; 4B90B7A6133AD87D00BD33CB /* OFListenFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B90B79C133AD87D00BD33CB /* OFListenFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B90B7A7133AD87D00BD33CB /* OFListenFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90B79D133AD87D00BD33CB /* OFListenFailedException.m */; }; + 4B989C2F13771A3700109A30 /* OFSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B989C2E13771A3700109A30 /* OFSerialization.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BD98C03133814220048DD5B /* objfw-defs.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD98C011338140B0048DD5B /* objfw-defs.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BDF37B51338055600F9A81A /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BDF37B41338055600F9A81A /* config.h */; }; 4BF33AFB133807590059CEF7 /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B3D23761337FBC800DD29B8 /* ObjFW.framework */; }; 4BF33AFC133807A20059CEF7 /* OFArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6EF66E1235358D0076B512 /* OFArrayTests.m */; }; 4BF33AFD133807A20059CEF7 /* OFBlockTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BE5F0E412DF4259005C7A0C /* OFBlockTests.m */; }; @@ -509,10 +510,11 @@ 4B90B79B133AD87D00BD33CB /* OFConnectionFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFConnectionFailedException.m; path = src/exceptions/OFConnectionFailedException.m; sourceTree = ""; }; 4B90B79C133AD87D00BD33CB /* OFListenFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFListenFailedException.h; path = src/exceptions/OFListenFailedException.h; sourceTree = ""; }; 4B90B79D133AD87D00BD33CB /* OFListenFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFListenFailedException.m; path = src/exceptions/OFListenFailedException.m; sourceTree = ""; }; 4B981CDE116F71DD00294DB7 /* OFSeekableStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFSeekableStream.h; path = src/OFSeekableStream.h; sourceTree = ""; }; 4B981CDF116F71DD00294DB7 /* OFSeekableStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFSeekableStream.m; path = src/OFSeekableStream.m; sourceTree = ""; }; + 4B989C2E13771A3700109A30 /* OFSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFSerialization.h; path = src/OFSerialization.h; sourceTree = ""; }; 4B99250F12E0780000215DBE /* OFHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFHTTPRequest.h; path = src/OFHTTPRequest.h; sourceTree = ""; }; 4B99251012E0780000215DBE /* OFHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFHTTPRequest.m; path = src/OFHTTPRequest.m; sourceTree = ""; }; 4BAF5F46123460C900F4E111 /* OFCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFCollection.h; path = src/OFCollection.h; sourceTree = ""; }; 4BAF5F47123460C900F4E111 /* OFStreamObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStreamObserver.h; path = src/OFStreamObserver.h; sourceTree = ""; }; 4BAF5F48123460C900F4E111 /* OFStreamObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamObserver.m; path = src/OFStreamObserver.m; sourceTree = ""; }; @@ -786,10 +788,11 @@ 4B6799781099E7C50041064A /* OFObject.m */, 4B6799791099E7C50041064A /* OFPlugin.h */, 4B67997A1099E7C50041064A /* OFPlugin.m */, 4B981CDE116F71DD00294DB7 /* OFSeekableStream.h */, 4B981CDF116F71DD00294DB7 /* OFSeekableStream.m */, + 4B989C2E13771A3700109A30 /* OFSerialization.h */, 4BF1BCC411C9663F0025511F /* OFSHA1Hash.h */, 4BF1BCC511C9663F0025511F /* OFSHA1Hash.m */, 4B67997D1099E7C50041064A /* OFStream.h */, 4B67997E1099E7C50041064A /* OFStream.m */, 4BAF5F47123460C900F4E111 /* OFStreamObserver.h */, @@ -945,10 +948,11 @@ 4B3D23CF1337FCB000DD29B8 /* OFMutableString.h in Headers */, 4B3D23D01337FCB000DD29B8 /* OFNumber.h in Headers */, 4B3D23D11337FCB000DD29B8 /* OFObject.h in Headers */, 4B3D23D21337FCB000DD29B8 /* OFPlugin.h in Headers */, 4B3D23D31337FCB000DD29B8 /* OFSeekableStream.h in Headers */, + 4B989C2F13771A3700109A30 /* OFSerialization.h in Headers */, 4B3D23D41337FCB000DD29B8 /* OFSHA1Hash.h in Headers */, 4B3D23D51337FCB000DD29B8 /* OFStream.h in Headers */, 4B3D23D61337FCB000DD29B8 /* OFStreamObserver.h in Headers */, 4B3D23D71337FCB000DD29B8 /* OFStreamSocket.h in Headers */, 4B3D23D81337FCB000DD29B8 /* OFString.h in Headers */, Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -49,10 +49,11 @@ of_asprintf.m \ unicode.m INCLUDES := ${SRCS:.m=.h} \ OFCollection.h \ + OFSerialization.h \ ObjFW.h \ asprintf.h \ ${ATOMIC_H} \ macros.h \ objfw-defs.h \ Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -17,10 +17,11 @@ #include #import "OFObject.h" #import "OFCollection.h" #import "OFEnumerator.h" +#import "OFSerialization.h" @class OFDataArray; @class OFString; #ifdef OF_HAVE_BLOCKS @@ -32,11 +33,11 @@ /** * \brief A class for storing objects in an array. */ @interface OFArray: OFObject + OFFastEnumeration, OFSerialization> { OFDataArray *array; } /** Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -419,10 +419,55 @@ [pool release]; [ret autorelease]; + /* + * Class swizzle the string to be immutable. We declared the return type + * to be OFString*, so it can't be modified anyway. But not swizzling it + * would create a real copy each time -[copy] is called. + */ + ret->isa = [OFString class]; + return ret; +} + +- (OFString*)stringBySerializing +{ + OFAutoreleasePool *pool; + OFMutableString *ret; + OFObject **cArray; + size_t i, count; + IMP append; + + if ([array count] == 0) { + if ([self isKindOfClass: [OFMutableArray class]]) + return @"()"; + else + return @"<0>()"; + } + + cArray = [array cArray]; + count = [array count]; + if ([self isKindOfClass: [OFMutableArray class]]) + ret = [OFMutableString stringWithFormat: @"(", + count]; + else + ret = [OFMutableString stringWithFormat: @"<%zd>(", count]; + pool = [[OFAutoreleasePool alloc] init]; + append = [ret methodForSelector: @selector(appendString:)]; + + for (i = 0; i < count - 1; i++) { + append(ret, @selector(appendString:), + [cArray[i] stringBySerializing]); + append(ret, @selector(appendString:), @", "); + + [pool releaseObjects]; + } + [ret appendFormat: @"%@)", [cArray[i] stringBySerializing]]; + + [pool release]; + /* * Class swizzle the string to be immutable. We declared the return type * to be OFString*, so it can't be modified anyway. But not swizzling it * would create a real copy each time -[copy] is called. */ Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -17,10 +17,11 @@ #include #import "OFObject.h" #import "OFCollection.h" #import "OFEnumerator.h" +#import "OFSerialization.h" @class OFArray; #ifdef OF_HAVE_BLOCKS typedef void (^of_dictionary_enumeration_block_t)(id key, id object, @@ -38,11 +39,11 @@ /** * \brief A class for storing objects in a hash table. */ @interface OFDictionary: OFObject + OFFastEnumeration, OFSerialization> { struct of_dictionary_bucket **data; uint32_t size; size_t count; } Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -714,12 +714,11 @@ - (OFString*)description { OFMutableString *ret; OFAutoreleasePool *pool, *pool2; - OFEnumerator *keyEnumerator; - OFEnumerator *objectEnumerator; + OFEnumerator *keyEnumerator, *objectEnumerator; id key, object; size_t i; if (count == 0) return @"{}"; @@ -745,10 +744,61 @@ } [ret replaceOccurrencesOfString: @"\n" withString: @"\n\t"]; [ret appendString: @";\n}"]; + [pool release]; + + /* + * Class swizzle the string to be immutable. We declared the return type + * to be OFString*, so it can't be modified anyway. But not swizzling it + * would create a real copy each time -[copy] is called. + */ + ret->isa = [OFString class]; + return ret; +} + +- (OFString*)stringBySerializing +{ + OFMutableString *ret; + OFAutoreleasePool *pool, *pool2; + OFEnumerator *keyEnumerator, *objectEnumerator; + id key, object; + size_t i; + + if (count == 0) { + if ([self isKindOfClass: [OFMutableDictionary class]]) + return @"{}"; + else + return @"<0>{}"; + } + + if ([self isKindOfClass: [OFMutableDictionary class]]) + ret = [OFMutableString stringWithFormat: @"{", + count]; + else + ret = [OFMutableString stringWithFormat: @"<%zd>{", count]; + pool = [[OFAutoreleasePool alloc] init]; + keyEnumerator = [self keyEnumerator]; + objectEnumerator = [self objectEnumerator]; + + i = 0; + pool2 = [[OFAutoreleasePool alloc] init]; + + while ((key = [keyEnumerator nextObject]) != nil && + (object = [objectEnumerator nextObject]) != nil) { + [ret appendString: [key stringBySerializing]]; + [ret appendString: @" = "]; + [ret appendString: [object stringBySerializing]]; + + if (++i < count) + [ret appendString: @"; "]; + + [pool2 releaseObjects]; + } + [ret appendString: @"}"]; + [pool release]; /* * Class swizzle the string to be immutable. We declared the return type * to be OFString*, so it can't be modified anyway. But not swizzling it Index: src/OFNumber.h ================================================================== --- src/OFNumber.h +++ src/OFNumber.h @@ -15,10 +15,11 @@ */ #include #import "OFObject.h" +#import "OFSerialization.h" /** * \brief The type of a number. */ typedef enum of_number_type_t { @@ -51,11 +52,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 @@ -1080,13 +1080,98 @@ case OF_NUMBER_INTMAX: case OF_NUMBER_PTRDIFF: case OF_NUMBER_INTPTR: return [OFString stringWithFormat: @"%jd", [self intMaxValue]]; case OF_NUMBER_FLOAT: - return [OFString stringWithFormat: @"%f", [self floatValue]]; + return [OFString stringWithFormat: @"%f", value.float_]; + case OF_NUMBER_DOUBLE: + return [OFString stringWithFormat: @"%lf", value.double_]; + default: + @throw [OFInvalidFormatException newWithClass: isa]; + } +} + +- (OFString*)stringBySerializing +{ + switch (type) { + case OF_NUMBER_BOOL: + return (value.bool_ ? @"1" : @"0"); + case OF_NUMBER_UCHAR: + return [OFString stringWithFormat: @"%hhu", + value.uchar]; + case OF_NUMBER_USHORT: + return [OFString stringWithFormat: @"%hu", + value.ushort]; + case OF_NUMBER_UINT: + return [OFString stringWithFormat: @"%u", + value.uint]; + case OF_NUMBER_ULONG: + return [OFString stringWithFormat: @"%lu", + value.ulong]; + case OF_NUMBER_UINT8: + return [OFString stringWithFormat: @"%" @PRIu8, + value.uint8]; + case OF_NUMBER_UINT16: + return [OFString stringWithFormat: @"%" @PRIu16, + value.uint16]; + case OF_NUMBER_UINT32: + return [OFString stringWithFormat: @"%" @PRIu32, + value.uint32]; + case OF_NUMBER_UINT64: + return [OFString stringWithFormat: @"%" @PRIu64, + value.uint64]; + case OF_NUMBER_SIZE: + return [OFString stringWithFormat: @"%ju", + (uintmax_t)value.size]; + case OF_NUMBER_UINTMAX: + return [OFString stringWithFormat: @"%ju", + value.uintmax]; + case OF_NUMBER_UINTPTR: + return [OFString stringWithFormat: @"%" @PRIuPTR, + value.uintptr]; + case OF_NUMBER_CHAR: + return [OFString stringWithFormat: @"%hhd", + value.char_]; + case OF_NUMBER_SHORT: + return [OFString stringWithFormat: @"%hd", + value.short_]; + case OF_NUMBER_INT: + return [OFString stringWithFormat: @"%d", + value.int_]; + case OF_NUMBER_LONG: + return [OFString stringWithFormat: @"%ld", + value.long_]; + case OF_NUMBER_INT8: + return [OFString stringWithFormat: @"%" @PRId8, + value.int8]; + case OF_NUMBER_INT16: + return [OFString stringWithFormat: @"%" @PRId16, + value.int16]; + case OF_NUMBER_INT32: + return [OFString stringWithFormat: @"%" @PRId32, + value.int32]; + case OF_NUMBER_INT64: + return [OFString stringWithFormat: @"%" @PRId64, + value.int64]; + case OF_NUMBER_SSIZE: + return [OFString stringWithFormat: @"%jd", + (intmax_t)value.ssize]; + case OF_NUMBER_INTMAX: + return [OFString stringWithFormat: @"%jd", + value.intmax]; + case OF_NUMBER_PTRDIFF: + return [OFString stringWithFormat: @"%td" @PRIdPTR, + value.ptrdiff]; + case OF_NUMBER_INTPTR: + return [OFString stringWithFormat: @"%" @PRIdPTR, + value.intptr]; + case OF_NUMBER_FLOAT: + return [OFString stringWithFormat: @"%f", + value.float_]; case OF_NUMBER_DOUBLE: - return [OFString stringWithFormat: @"%lf", [self doubleValue]]; + return [OFString stringWithFormat: @"%lf", + value.double_]; default: @throw [OFInvalidFormatException newWithClass: isa]; } } @end ADDED src/OFSerialization.h Index: src/OFSerialization.h ================================================================== --- src/OFSerialization.h +++ src/OFSerialization.h @@ -0,0 +1,27 @@ +/* + * 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 protocol for serializing objects. + */ +@protocol OFSerialization +/** + * \brief Serializes the object into a string. + */ +- (OFString*)stringBySerializing; +@end Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -17,10 +17,11 @@ #include #include #include #import "OFObject.h" +#import "OFSerialization.h" typedef uint32_t of_unichar_t; /** * \brief The encoding of a string. @@ -50,11 +51,12 @@ @class OFURL; /** * \brief A class for handling strings. */ -@interface OFString: OFObject +@interface OFString: OFObject { char *string; size_t length; BOOL isUTF8; } Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -1052,10 +1052,33 @@ - (OFString*)description { return [[self copy] autorelease]; } + +- (OFString*)stringBySerializing +{ + OFMutableString *serialization = [[self mutableCopy] autorelease]; + [serialization replaceOccurrencesOfString: @"\\" + withString: @"\\\\"]; + [serialization replaceOccurrencesOfString: @"\"" + withString: @"\\\""]; + + if ([self isKindOfClass: [OFMutableString class]]) + [serialization prependString: @"\""]; + else + [serialization prependString: @"\""]; + [serialization appendString: @"\""]; + + /* + * Class swizzle the string to be immutable. We declared the return type + * to be OFString*, so it can't be modified anyway. But not swizzling it + * would create a real copy each time -[copy] is called. + */ + serialization->isa = [OFString class]; + return serialization; +} - (of_unichar_t)characterAtIndex: (size_t)index { of_unichar_t c;