Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -229,10 +229,11 @@ 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, ); }; }; + 4BC5E7D6137F0D0E0076F962 /* OFSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC5E7D5137F0D0E0076F962 /* OFSerialization.m */; }; 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 */; }; @@ -522,10 +523,11 @@ 4BAF5F4A123460C900F4E111 /* OFStreamSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamSocket.m; path = src/OFStreamSocket.m; sourceTree = ""; }; 4BB50DCF12F863C700C9393F /* of_asprintf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = of_asprintf.h; path = src/of_asprintf.h; sourceTree = SOURCE_ROOT; }; 4BB50DD012F863C700C9393F /* of_asprintf.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = of_asprintf.m; path = src/of_asprintf.m; sourceTree = SOURCE_ROOT; }; 4BBA36C411406AB700CBA3AC /* atomic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = atomic.h; path = src/atomic.h; sourceTree = ""; }; 4BBA36C511406AB700CBA3AC /* macros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macros.h; path = src/macros.h; sourceTree = ""; }; + 4BC5E7D5137F0D0E0076F962 /* OFSerialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFSerialization.m; path = src/OFSerialization.m; sourceTree = ""; }; 4BD86D801237A6C600ED9912 /* OFBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFBlock.h; path = src/OFBlock.h; sourceTree = SOURCE_ROOT; }; 4BD86D811237A6C600ED9912 /* OFBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFBlock.m; path = src/OFBlock.m; sourceTree = SOURCE_ROOT; }; 4BD98C011338140B0048DD5B /* objfw-defs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objfw-defs.h"; path = "src/objfw-defs.h"; sourceTree = SOURCE_ROOT; }; 4BDF37B41338055600F9A81A /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = SOURCE_ROOT; }; 4BE17AD812FD744C002CEB0B /* foundation-compat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "foundation-compat.m"; path = "src/foundation-compat.m"; sourceTree = SOURCE_ROOT; }; @@ -789,10 +791,11 @@ 4B6799791099E7C50041064A /* OFPlugin.h */, 4B67997A1099E7C50041064A /* OFPlugin.m */, 4B981CDE116F71DD00294DB7 /* OFSeekableStream.h */, 4B981CDF116F71DD00294DB7 /* OFSeekableStream.m */, 4B989C2E13771A3700109A30 /* OFSerialization.h */, + 4BC5E7D5137F0D0E0076F962 /* OFSerialization.m */, 4BF1BCC411C9663F0025511F /* OFSHA1Hash.h */, 4BF1BCC511C9663F0025511F /* OFSHA1Hash.m */, 4B67997D1099E7C50041064A /* OFStream.h */, 4B67997E1099E7C50041064A /* OFStream.m */, 4BAF5F47123460C900F4E111 /* OFStreamObserver.h */, @@ -1268,10 +1271,11 @@ 4B55A104133ABEA900B58A93 /* OFThreadStillRunningException.m in Sources */, 4B17FFAA133A34E7003E6DCD /* OFTruncatedDataException.m in Sources */, 4B17FFB6133A375B003E6DCD /* OFUnboundNamespaceException.m in Sources */, 4B17FFB2133A3664003E6DCD /* OFUnsupportedProtocolException.m in Sources */, 4B55A117133AC24600B58A93 /* OFWriteFailedException.m in Sources */, + 4BC5E7D6137F0D0E0076F962 /* OFSerialization.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 4BF33AEC133807310059CEF7 /* Sources */ = { isa = PBXSourcesBuildPhase; Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -27,10 +27,11 @@ OFMutableString.m \ OFNumber.m \ OFObject.m \ ${OFPLUGIN_M} \ OFSeekableStream.m \ + OFSerialization.m \ OFSHA1Hash.m \ OFStream.m \ OFStreamObserver.m \ OFStreamSocket.m \ OFString.m \ @@ -49,11 +50,10 @@ 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.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -23,10 +23,11 @@ #import "OFString.h" #import "OFXMLElement.h" #import "OFAutoreleasePool.h" #import "OFEnumerationMutationException.h" +#import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" #import "macros.h" @implementation OFArray @@ -219,10 +220,51 @@ [objects[i] release]; [self release]; @throw e; } + + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + self = [self init]; + + @try { + OFAutoreleasePool *pool, *pool2; + OFEnumerator *enumerator; + OFXMLElement *child; + + pool = [[OFAutoreleasePool alloc] init]; + + if (![[element name] isEqual: @"object"] || + ![[element namespace] isEqual: OF_SERIALIZATION_NS] || + ![[[element attributeForName: @"class"] stringValue] + isEqual: [isa className]]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + enumerator = [[element + elementsForName: @"object" + namespace: OF_SERIALIZATION_NS] objectEnumerator]; + pool2 = [[OFAutoreleasePool alloc] init]; + while ((child = [enumerator nextObject]) != nil) { + id object = [OFSerialization + objectByDeserializingXMLElement: child]; + + [array addItem: &object]; + [object retain]; + + [pool2 releaseObjects]; + } + + [pool release]; + } @catch (id e) { + [self release]; + @throw e; + } return self; } - (size_t)count Index: src/OFDate.m ================================================================== --- src/OFDate.m +++ src/OFDate.m @@ -236,10 +236,48 @@ seconds += seconds_; microseconds += microseconds_; seconds += microseconds / 1000000; microseconds %= 1000000; + + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + self = [super init]; + + @try { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFXMLElement *secondsElement, *microsecondsElement; + + if (![[element name] isEqual: @"object"] || + ![[element namespace] isEqual: OF_SERIALIZATION_NS] || + ![[[element attributeForName: @"class"] stringValue] + isEqual: [isa className]]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + secondsElement = [element elementForName: @"seconds" + namespace: OF_SERIALIZATION_NS]; + microsecondsElement = [element + elementForName: @"microseconds" + namespace: OF_SERIALIZATION_NS]; + + if (secondsElement == nil || microsecondsElement == nil) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + seconds = (int64_t)[[secondsElement stringValue] decimalValue]; + microseconds = + (uint32_t)[[microsecondsElement stringValue] decimalValue]; + + [pool release]; + } @catch (id e) { + [self release]; + @throw e; + } return self; } - (BOOL)isEqual: (id)object Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -464,10 +464,75 @@ @throw e; } data[j]->object = object; } + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + @try { + OFAutoreleasePool *pool, *pool2; + OFMutableDictionary *dictionary; + OFArray *pairs; + OFEnumerator *enumerator; + OFXMLElement *pair; + + pool = [[OFAutoreleasePool alloc] init]; + + if (![[element name] isEqual: @"object"] || + ![[element namespace] isEqual: OF_SERIALIZATION_NS] || + ![[[element attributeForName: @"class"] stringValue] + isEqual: [isa className]]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + dictionary = [OFMutableDictionary dictionary]; + pairs = [element elementsForName: @"pair" + namespace: OF_SERIALIZATION_NS]; + + enumerator = [pairs objectEnumerator]; + pool2 = [[OFAutoreleasePool alloc] init]; + while ((pair = [enumerator nextObject]) != nil) { + OFXMLElement *keyElement, *valueElement; + id key; + id object; + + keyElement = [pair elementForName: @"key" + namespace: OF_SERIALIZATION_NS]; + valueElement = [pair + elementForName: @"value" + namespace: OF_SERIALIZATION_NS]; + + if (keyElement == nil || valueElement == nil) + @throw [OFInvalidArgumentException + newWithClass: isa + selector: _cmd]; + + key = [OFSerialization objectByDeserializingXMLElement: + [keyElement elementForName: @"object" + namespace: OF_SERIALIZATION_NS]]; + object = [OFSerialization + objectByDeserializingXMLElement: + [valueElement elementForName: @"object" + namespace: OF_SERIALIZATION_NS]]; + + [dictionary setObject: object + forKey: key]; + + [pool2 releaseObjects]; + } + + self = [self initWithDictionary: dictionary]; + + [pool release]; } @catch (id e) { [self release]; @throw e; } Index: src/OFList.m ================================================================== --- src/OFList.m +++ src/OFList.m @@ -22,25 +22,56 @@ #import "OFString.h" #import "OFXMLElement.h" #import "OFAutoreleasePool.h" #import "OFEnumerationMutationException.h" +#import "OFInvalidArgumentException.h" #import "macros.h" @implementation OFList + list { return [[[self alloc] init] autorelease]; } -- init +- initWithSerialization: (OFXMLElement*)element { - self = [super init]; + self = [self init]; - firstListObject = NULL; - lastListObject = NULL; + @try { + OFAutoreleasePool *pool, *pool2; + OFEnumerator *enumerator; + OFXMLElement *child; + + pool = [[OFAutoreleasePool alloc] init]; + + if (![[element name] isEqual: @"object"] || + ![[element namespace] isEqual: OF_SERIALIZATION_NS] || + ![[[element attributeForName: @"class"] stringValue] + isEqual: [isa className]]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + enumerator = [[element + elementsForName: @"object" + namespace: OF_SERIALIZATION_NS] objectEnumerator]; + pool2 = [[OFAutoreleasePool alloc] init]; + while ((child = [enumerator nextObject]) != nil) { + id object = [OFSerialization + objectByDeserializingXMLElement: child]; + + [self appendObject: object]; + + [pool2 releaseObjects]; + } + + [pool release]; + } @catch (id e) { + [self release]; + @throw e; + } return self; } - (void)dealloc @@ -175,22 +206,16 @@ [self freeMemory: listObject]; } - (id)firstObject { - if (firstListObject != NULL) - return firstListObject->object; - - return nil; + return (firstListObject != NULL ? firstListObject->object : nil); } - (id)lastObject { - if (lastListObject != NULL) - return lastListObject->object; - - return nil; + return (lastListObject != NULL ? lastListObject->object : nil); } - (size_t)count { return count; Index: src/OFNumber.m ================================================================== --- src/OFNumber.m +++ src/OFNumber.m @@ -21,10 +21,11 @@ #import "OFNumber.h" #import "OFString.h" #import "OFXMLElement.h" #import "OFAutoreleasePool.h" +#import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotImplementedException.h" #import "macros.h" @@ -701,10 +702,67 @@ { self = [super init]; value.double_ = double_; type = OF_NUMBER_DOUBLE; + + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + self = [super init]; + + @try { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFString *typeString; + + if (![[element name] isEqual: @"object"] || + ![[element namespace] isEqual: OF_SERIALIZATION_NS] || + ![[[element attributeForName: @"class"] stringValue] + isEqual: [isa className]]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + typeString = [[element attributeForName: @"type"] stringValue]; + + if ([typeString isEqual: @"boolean"]) { + type = OF_NUMBER_BOOL; + + if ([[element stringValue] isEqual: @"YES"]) + value.bool_ = YES; + else if ([[element stringValue] isEqual: @"NO"]) + value.bool_ = NO; + else + @throw [OFInvalidArgumentException + newWithClass: isa + selector: _cmd]; + } else if ([typeString isEqual: @"unsigned"]) { + /* + * FIXME: This will fail if the value is bigger than + * INTMAX_MAX! + */ + type = OF_NUMBER_UINTMAX; + value.uintmax = [[element stringValue] decimalValue]; + } else if ([typeString isEqual: @"signed"]) { + type = OF_NUMBER_INTMAX; + value.intmax = [[element stringValue] decimalValue]; + } else if ([typeString isEqual: @"float"]) { + type = OF_NUMBER_FLOAT; + value.float_ = [[element stringValue] floatValue]; + } else if ([typeString isEqual: @"double"]) { + type = OF_NUMBER_DOUBLE; + value.double_ = [[element stringValue] doubleValue]; + } else + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + [pool release]; + } @catch (id e) { + [self release]; + @throw e; + } return self; } - (of_number_type_t)type Index: src/OFSerialization.h ================================================================== --- src/OFSerialization.h +++ src/OFSerialization.h @@ -12,21 +12,61 @@ * 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. */ +#import "OFObject.h" + @class OFString; @class OFXMLElement; #define OF_SERIALIZATION_NS @"https://webkeks.org/objfw/serialization" /** * \brief A protocol for serializing objects. */ @protocol OFSerialization +/** + * \brief Initializes the object with the specified XML element serialization. + * + * \param element An OFXMLElement with the serialized object + * \return An initialized object + */ +- initWithSerialization: (OFXMLElement*)element; + /** * \brief Serializes the object into an XML element. * * \return The object serialized into an XML element */ - (OFXMLElement*)XMLElementBySerializing; @end + +/** + * \brief A class that provides class methods for serializing and deserializing + * objects. + */ +@interface OFSerialization: OFObject +/** + * \brief Creates a string by serializing the specified object. + * + * \param object The object to serialize + * \return The object serialized as a string + */ ++ (OFString*)stringBySerializingObject: (id )object; + +/** + * \brief Deserializes the specified string into an object. + * + * \param string The string describing the serialized object + * \return The deserialized object + */ ++ (id)objectByDeserializingString: (OFString*)string; + +/** + * \brief Deserializes the specified XML element into an object. + * + * \param string The XML element describing the serialized object + * \return The deserialized object + */ ++ (id)objectByDeserializingXMLElement: (OFXMLElement*)element; +@end ADDED src/OFSerialization.m Index: src/OFSerialization.m ================================================================== --- src/OFSerialization.m +++ src/OFSerialization.m @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#include "config.h" + +#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME) +# import +#endif + +#import "OFSerialization.h" +#import "OFString.h" +#import "OFArray.h" +#import "OFXMLElement.h" +#import "OFAutoreleasePool.h" + +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" +#import "OFNotImplementedException.h" + +#if defined(OF_OBJFW_RUNTIME) || defined(OF_OLD_GNU_RUNTIME) +# define objc_lookUpClass objc_lookup_class +#endif + +@implementation OFSerialization ++ (OFString*)stringBySerializingObject: (id )object +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFXMLElement *element = [object XMLElementBySerializing]; + OFXMLElement *root; + OFString *ret; + + root = [OFXMLElement elementWithName: @"serialization" + namespace: OF_SERIALIZATION_NS]; + [root addChild: element]; + + ret = [@"\n" + stringByAppendingString: [root XMLString]]; + [ret retain]; + + @try { + [pool release]; + } @catch (id e) { + [ret release]; + } + + return [ret autorelease]; +} + ++ (id)objectByDeserializingString: (OFString*)string +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFXMLElement *root = [OFXMLElement elementWithXMLString: string]; + OFXMLElement *element; + id object; + + if ([[root children] count] != 1) + @throw [OFInvalidArgumentException newWithClass: self + selector: _cmd]; + + element = [[root children] firstObject]; + object = [[self objectByDeserializingXMLElement: element] retain]; + + @try { + [pool release]; + } @catch (id e) { + [object release]; + @throw e; + } + + return [object autorelease]; +} + ++ (id)objectByDeserializingXMLElement: (OFXMLElement*)element +{ + OFAutoreleasePool *pool; + OFString *className; + Class class; + id object; + + if (element == nil) + return nil; + + pool = [[OFAutoreleasePool alloc] init]; + className = [[element attributeForName: @"class"] stringValue]; + if (className == nil) + @throw [OFInvalidArgumentException newWithClass: self + selector: _cmd]; + + class = objc_lookUpClass([className cString]); + if (class == Nil) + @throw [OFNotImplementedException newWithClass: Nil]; + + if (![class instancesRespondToSelector: + @selector(initWithSerialization:)]) + @throw [OFNotImplementedException + newWithClass: class + selector: @selector(initWithSerialization:)]; + + object = [[class alloc] initWithSerialization: element]; + + @try { + [pool release]; + } @catch (id e) { + [object release]; + @throw e; + } + + return [object autorelease]; +} + +- init +{ + Class c = isa; + [self release]; + @throw [OFNotImplementedException newWithClass: c + selector: _cmd]; +} +@end Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -757,11 +757,11 @@ for (i = 0; i < length_; i++) { of_unichar_t character = (swap ? of_bswap16(string_[i]) : string_[i]); size_t characterLen; - /* Missed the high surrogate */ + /* Missing high surrogate */ if ((character & 0xFC00) == 0xDC00) @throw [OFInvalidEncodingException newWithClass: isa]; if ((character & 0xFC00) == 0xD800) { @@ -1069,10 +1069,33 @@ self = [[c alloc] initWithCString: (char*)[[result data] cArray] encoding: encoding length: [[result data] count]]; [pool release]; + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + @try { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + + if (![[element name] isEqual: @"object"] || + ![[element namespace] isEqual: OF_SERIALIZATION_NS] || + ![[[element attributeForName: @"class"] stringValue] + isEqual: [isa className]]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + self = [self initWithString: [element stringValue]]; + + [pool release]; + } @catch (id e) { + [self release]; + @throw e; + } + return self; } - (const char*)cString { Index: src/OFURL.m ================================================================== --- src/OFURL.m +++ src/OFURL.m @@ -285,10 +285,33 @@ [self release]; @throw e; } @finally { free(cString2); } + + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + @try { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + + if (![[element name] isEqual: @"object"] || + ![[element namespace] isEqual: OF_SERIALIZATION_NS] || + ![[[element attributeForName: @"class"] stringValue] + isEqual: [isa className]]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + self = [self initWithString: [element stringValue]]; + + [pool release]; + } @catch (id e) { + [self release]; + @throw e; + } return self; } - (void)dealloc Index: src/OFXMLAttribute.m ================================================================== --- src/OFXMLAttribute.m +++ src/OFXMLAttribute.m @@ -20,10 +20,12 @@ #import "OFString.h" #import "OFDictionary.h" #import "OFXMLElement.h" #import "OFAutoreleasePool.h" +#import "OFInvalidArgumentException.h" + @implementation OFXMLAttribute + attributeWithName: (OFString*)name namespace: (OFString*)ns stringValue: (OFString*)value { @@ -40,10 +42,43 @@ @try { name = [name_ copy]; ns = [ns_ copy]; stringValue = [value copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + self = [super init]; + + @try { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + + if (![[element name] isEqual: @"object"] || + ![[element namespace] isEqual: OF_SERIALIZATION_NS] || + ![[[element attributeForName: @"class"] stringValue] + isEqual: [isa className]]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + name = [[[element + elementForName: @"name" + namespace: OF_SERIALIZATION_NS] stringValue] retain]; + ns = [[[element + elementForName: @"namespace" + namespace: OF_SERIALIZATION_NS] stringValue] retain]; + stringValue = [[[element + elementForName: @"stringValue" + namespace: OF_SERIALIZATION_NS] stringValue] retain]; + + [pool release]; } @catch (id e) { [self release]; @throw e; } Index: src/OFXMLElement.m ================================================================== --- src/OFXMLElement.m +++ src/OFXMLElement.m @@ -155,23 +155,17 @@ @try { name = [name_ copy]; ns = [ns_ copy]; - if (stringValue != nil) { - OFAutoreleasePool *pool; - - pool = [[OFAutoreleasePool alloc] init]; - [self addChild: - [OFXMLElement elementWithCharacters: stringValue]]; - [pool release]; - } - namespaces = [[OFMutableDictionary alloc] initWithKeysAndObjects: @"http://www.w3.org/XML/1998/namespace", @"xml", @"http://www.w3.org/2000/xmlns/", @"xmlns", nil]; + + if (stringValue != nil) + [self setStringValue: stringValue]; } @catch (id e) { [self release]; @throw e; } @@ -270,10 +264,83 @@ parser: parser]; self = [delegate->element retain]; @try { + [pool release]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + self = [super init]; + + @try { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFXMLElement *attributesElement, *namespacesElement; + OFXMLElement *childrenElement; + + if (![[element name] isEqual: @"object"] || + ![[element namespace] isEqual: OF_SERIALIZATION_NS] || + ![[[element attributeForName: @"class"] stringValue] + isEqual: [isa className]]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + name = [[[element + elementForName: @"name" + namespace: OF_SERIALIZATION_NS] stringValue] copy]; + ns = [[[element + elementForName: @"namespace" + namespace: OF_SERIALIZATION_NS] stringValue] copy]; + defaultNamespace = [[[element + elementForName: @"defaultNamespace" + namespace: OF_SERIALIZATION_NS] stringValue] copy]; + characters = [[[element + elementForName: @"characters" + namespace: OF_SERIALIZATION_NS] stringValue] copy]; + CDATA = [[[element + elementForName: @"CDATA" + namespace: OF_SERIALIZATION_NS] stringValue] copy]; + comment = [[[element + elementForName: @"comment" + namespace: OF_SERIALIZATION_NS] stringValue] copy]; + + attributesElement = [element + elementForName: @"attributes" + namespace: OF_SERIALIZATION_NS]; + namespacesElement = [element + elementForName: @"namespaces" + namespace: OF_SERIALIZATION_NS]; + childrenElement = [element elementForName: @"children" + namespace: OF_SERIALIZATION_NS]; + + attributes = [[OFSerialization objectByDeserializingXMLElement: + [attributesElement elementForName: @"object" + namespace: OF_SERIALIZATION_NS]] + retain]; + namespaces = [[OFSerialization objectByDeserializingXMLElement: + [namespacesElement elementForName: @"object" + namespace: OF_SERIALIZATION_NS]] + retain]; + children = [[OFSerialization objectByDeserializingXMLElement: + [childrenElement elementForName: @"object" + namespace: OF_SERIALIZATION_NS]] + retain]; + + if (!((name != nil || ns != nil || defaultNamespace != nil || + [attributes count] > 0 || [namespaces count] > 0 || + [children count] > 0) ^ (characters != nil) ^ + (CDATA != nil) ^ (comment != nil))) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + [pool release]; } @catch (id e) { [self release]; @throw e; }