Index: src/OFCountedSet.m ================================================================== --- src/OFCountedSet.m +++ src/OFCountedSet.m @@ -18,10 +18,11 @@ #import "OFCountedSet.h" #import "OFCountedSet_hashtable.h" #import "OFNumber.h" #import "OFString.h" +#import "OFXMLElement.h" #import "OFAutoreleasePool.h" #import "OFNotImplementedException.h" static struct { @@ -61,10 +62,15 @@ arguments: (va_list)arguments { return [[OFCountedSet_hashtable alloc] initWithObject: firstObject arguments: arguments]; } + +- initWithSerialization: (OFXMLElement*)element +{ + return [[OFCountedSet_hashtable alloc] initWithSerialization: element]; +} - retain { return self; } @@ -164,10 +170,53 @@ - mutableCopy { return [[OFCountedSet alloc] initWithSet: self]; } + +- (OFXMLElement*)XMLElementBySerializing +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFAutoreleasePool *pool2; + OFXMLElement *element; + OFEnumerator *enumerator; + id object; + + element = [OFXMLElement elementWithName: @"OFCountedSet" + namespace: OF_SERIALIZATION_NS]; + + enumerator = [self objectEnumerator]; + + pool2 = [[OFAutoreleasePool alloc] init]; + while ((object = [enumerator nextObject]) != nil) { + OFXMLElement *objectElement; + OFString *count; + + count = + [OFString stringWithFormat: @"%zu", + [self countForObject: object]]; + + objectElement = [OFXMLElement + elementWithName: @"object" + namespace: OF_SERIALIZATION_NS]; + [objectElement addAttributeWithName: @"count" + stringValue: count]; + [objectElement addChild: [object XMLElementBySerializing]]; + [element addChild: objectElement]; + + [pool2 releaseObjects]; + } + + [element retain]; + @try { + [pool release]; + } @finally { + [element autorelease]; + } + + return element; +} #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsAndCountUsingBlock: (of_counted_set_enumeration_block_t)block { Index: src/OFCountedSet_hashtable.m ================================================================== --- src/OFCountedSet_hashtable.m +++ src/OFCountedSet_hashtable.m @@ -19,13 +19,18 @@ #define OF_COUNTED_SET_HASHTABLE_M #import "OFMutableSet_hashtable.h" #import "OFCountedSet_hashtable.h" #import "OFMutableDictionary_hashtable.h" +#import "OFString.h" #import "OFNumber.h" #import "OFArray.h" +#import "OFXMLElement.h" #import "OFAutoreleasePool.h" + +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" @implementation OFCountedSet_hashtable + (void)initialize { if (self == [OFCountedSet_hashtable class]) @@ -98,10 +103,64 @@ [self addObject: firstObject]; while ((object = va_arg(arguments, id)) != nil) [self addObject: object]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + self = [self init]; + + @try { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFAutoreleasePool *pool2; + OFArray *objects; + OFEnumerator *enumerator; + OFXMLElement *objectElement; + + if (![[element name] isEqual: @"OFCountedSet"] || + ![[element namespace] isEqual: OF_SERIALIZATION_NS]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + objects = [element elementsForName: @"object" + namespace: OF_SERIALIZATION_NS]; + + enumerator = [objects objectEnumerator]; + pool2 = [[OFAutoreleasePool alloc] init]; + + while ((objectElement = [enumerator nextObject]) != nil) { + OFXMLElement *object; + OFXMLAttribute *count; + OFNumber *number; + + object = [[objectElement elementsForNamespace: + OF_SERIALIZATION_NS] firstObject]; + count = [objectElement attributeForName: @"count"]; + + if (object == nil || count == nil) + @throw [OFInvalidFormatException + newWithClass: isa]; + + number = [OFNumber numberWithSize: + (size_t)[[count stringValue] decimalValue]]; + + [dictionary _setObject: number + forKey: [object objectByDeserializing] + copyKey: NO]; + + [pool2 releaseObjects]; + } + + [pool release]; } @catch (id e) { [self release]; @throw e; } Index: src/OFMutableSet.m ================================================================== --- src/OFMutableSet.m +++ src/OFMutableSet.m @@ -61,10 +61,15 @@ arguments: (va_list)arguments { return [[OFMutableSet_hashtable alloc] initWithObject: firstObject arguments: arguments]; } + +- initWithSerialization: (OFXMLElement*)element +{ + return [[OFMutableSet_hashtable alloc] initWithSerialization: element]; +} - retain { return self; } Index: src/OFSet.h ================================================================== --- src/OFSet.h +++ src/OFSet.h @@ -16,10 +16,11 @@ #include #import "OFObject.h" #import "OFCollection.h" +#import "OFSerialization.h" @class OFArray; #ifdef OF_HAVE_BLOCKS typedef void (^of_set_enumeration_block_t)(id object, BOOL *stop); @@ -27,11 +28,12 @@ #endif /** * \brief An unordered set of unique objects. */ -@interface OFSet: OFObject +@interface OFSet: OFObject /** * \brief Returns a new, autoreleased set. * * \return A new, autoreleased set */ Index: src/OFSet.m ================================================================== --- src/OFSet.m +++ src/OFSet.m @@ -17,10 +17,11 @@ #include "config.h" #import "OFSet.h" #import "OFSet_hashtable.h" #import "OFString.h" +#import "OFXMLElement.h" #import "OFAutoreleasePool.h" #import "OFNotImplementedException.h" static struct { @@ -60,10 +61,15 @@ arguments: (va_list)arguments { return [[OFSet_hashtable alloc] initWithObject: firstObject arguments: arguments]; } + +- initWithSerialization: (OFXMLElement*)element +{ + return [[OFSet_hashtable alloc] initWithSerialization: element]; +} - retain { return self; } @@ -170,10 +176,18 @@ } - initWithObject: (id)firstObject arguments: (va_list)arguments { + Class c = isa; + [self release]; + @throw [OFNotImplementedException newWithClass: c + selector: _cmd]; +} + +- initWithSerialization: (OFXMLElement*)element +{ Class c = isa; [self release]; @throw [OFNotImplementedException newWithClass: c selector: _cmd]; } @@ -314,10 +328,44 @@ [pool release]; return NO; } + +- (OFXMLElement*)XMLElementBySerializing +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFAutoreleasePool *pool2; + OFXMLElement *element; + OFEnumerator *enumerator; + id object; + + if ([self isKindOfClass: [OFMutableSet class]]) + element = [OFXMLElement elementWithName: @"OFMutableSet" + namespace: OF_SERIALIZATION_NS]; + else + element = [OFXMLElement elementWithName: @"OFSet" + namespace: OF_SERIALIZATION_NS]; + + enumerator = [self objectEnumerator]; + + pool2 = [[OFAutoreleasePool alloc] init]; + while ((object = [enumerator nextObject]) != nil) { + [element addChild: [object XMLElementBySerializing]]; + + [pool2 releaseObjects]; + } + + [element retain]; + @try { + [pool release]; + } @finally { + [element autorelease]; + } + + return element; +} #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsUsingBlock: (of_set_enumeration_block_t)block { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; Index: src/OFSet_hashtable.m ================================================================== --- src/OFSet_hashtable.m +++ src/OFSet_hashtable.m @@ -21,11 +21,14 @@ #import "OFSet_hashtable.h" #import "OFMutableDictionary_hashtable.h" #import "OFArray.h" #import "OFString.h" #import "OFNumber.h" +#import "OFXMLElement.h" #import "OFAutoreleasePool.h" + +#import "OFInvalidArgumentException.h" @implementation OFSet_hashtable - init { self = [super init]; @@ -108,10 +111,53 @@ while ((object = va_arg(arguments, id)) != nil) [dictionary _setObject: one forKey: object copyKey: NO]; + + [pool release]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + self = [self init]; + + @try { + OFAutoreleasePool *pool, *pool2; + OFNumber *one; + OFEnumerator *enumerator; + OFXMLElement *child; + + pool = [[OFAutoreleasePool alloc] init]; + + if ((![[element name] isEqual: @"OFSet"] && + ![[element name] isEqual: @"OFMutableSet"]) || + ![[element namespace] isEqual: OF_SERIALIZATION_NS]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + one = [OFNumber numberWithSize: 1]; + + enumerator = [[element children] objectEnumerator]; + pool2 = [[OFAutoreleasePool alloc] init]; + + while ((child = [enumerator nextObject]) != nil) { + if (![[child namespace] isEqual: OF_SERIALIZATION_NS]) + continue; + + [dictionary _setObject: one + forKey: [child objectByDeserializing] + copyKey: NO]; + + [pool2 releaseObjects]; + } [pool release]; } @catch (id e) { [self release]; @throw e; Index: tests/OFSerializationTests.m ================================================================== --- tests/OFSerializationTests.m +++ tests/OFSerializationTests.m @@ -18,10 +18,12 @@ #import "OFSerialization.h" #import "OFString.h" #import "OFArray.h" #import "OFDictionary.h" +#import "OFSet.h" +#import "OFCountedSet.h" #import "OFList.h" #import "OFNumber.h" #import "OFDate.h" #import "OFURL.h" #import "OFDataArray.h" @@ -56,10 +58,13 @@ [l appendObject: @"Hello"]; [l appendObject: @"Wo\rld!\nHow are you?"]; [l appendObject: [OFURL URLWithString: @"https://webkeks.org/"]]; [l appendObject: [OFXMLElement elementWithXMLString: @""]]; + [l appendObject: [OFSet setWithObjects: @"foo", @"foo", @"bar", nil]]; + [l appendObject: + [OFCountedSet setWithObjects: @"foo", @"foo", @"bar", nil]]; [d setObject: @"list" forKey: l]; [da addNItems: 39 Index: tests/serialization.xml ================================================================== --- tests/serialization.xml +++ tests/serialization.xml @@ -1,8 +1,32 @@ + + MDEyMzQ1Njc4OTo7PEFCQ0RFRkdISklLTE1OT1BRUlNUVVZXWFla + + + data + + + + Qu"xbar +test + 1234 + asd + + + + + Hello + + + Blub + + + B"la + Hello Wo ld! How are you? @@ -48,36 +72,24 @@ + + foo + bar + + + + foo + + + bar + + list - - - Qu"xbar -test - 1234 - asd - - - - - Hello - - - Blub - - - B"la - - - MDEyMzQ1Njc4OTo7PEFCQ0RFRkdISklLTE1OT1BRUlNUVVZXWFla - - - data -