@@ -46,13 +46,10 @@ _references_to_categories_of_OFXMLElement(void) { _OFXMLElement_Serialization_reference = 1; } -static Class charactersClass = Nil; -static Class CDATAClass = Nil; - @interface OFXMLElementElementBuilderDelegate: OFObject { @public OFXMLElement *_element; @@ -77,18 +74,10 @@ @implementation OFXMLElement @synthesize name = _name, namespace = _namespace; @synthesize defaultNamespace = _defaultNamespace; -+ (void)initialize -{ - if (self == [OFXMLElement class]) { - charactersClass = [OFXMLCharacters class]; - CDATAClass = [OFXMLCDATA class]; - } -} - + (instancetype)elementWithName: (OFString *)name { return [[[self alloc] initWithName: name] autorelease]; } @@ -424,11 +413,11 @@ return ret; } - (OFString *)of_XMLStringWithParent: (OFXMLElement *)parent - namespaces: (OFDictionary *)allNamespaces + namespaces: (OFDictionary *)allNS indentation: (unsigned int)indentation level: (unsigned int)level OF_DIRECT { void *pool; char *cString; @@ -437,33 +426,33 @@ OFString *ret; OFString *defaultNS; pool = objc_autoreleasePoolPush(); - parentPrefix = [allNamespaces objectForKey: + parentPrefix = [allNS objectForKey: (parent != nil && parent->_namespace != nil ? parent->_namespace : (OFString *)@"")]; /* Add the namespaces of the current element */ - if (allNamespaces != nil) { + if (allNS != nil) { OFEnumerator *keyEnumerator = [_namespaces keyEnumerator]; OFEnumerator *objectEnumerator = [_namespaces objectEnumerator]; OFMutableDictionary *tmp; OFString *key, *object; - tmp = [[allNamespaces mutableCopy] autorelease]; + tmp = [[allNS mutableCopy] autorelease]; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) [tmp setObject: object forKey: key]; - allNamespaces = tmp; + allNS = tmp; } else - allNamespaces = _namespaces; + allNS = _namespaces; - prefix = [allNamespaces objectForKey: + prefix = [allNS objectForKey: (_namespace != nil ? _namespace : (OFString *)@"")]; if (parent != nil && parent->_namespace != nil && parentPrefix == nil) defaultNS = parent->_namespace; else if (parent != nil && parent->_defaultNamespace != nil) @@ -471,198 +460,178 @@ else defaultNS = _defaultNamespace; i = 0; length = _name.UTF8StringLength + 3 + (level * indentation); - cString = [self allocMemoryWithSize: length]; - - memset(cString + i, ' ', level * indentation); - i += level * indentation; - - /* Start of tag */ - cString[i++] = '<'; - - if (prefix != nil && ![_namespace isEqual: defaultNS]) { - length += prefix.UTF8StringLength + 1; - @try { - cString = [self resizeMemory: cString - size: length]; - } @catch (id e) { - [self freeMemory: cString]; - @throw e; - } - - memcpy(cString + i, prefix.UTF8String, prefix.UTF8StringLength); - i += prefix.UTF8StringLength; - cString[i++] = ':'; - } - - memcpy(cString + i, _name.UTF8String, _name.UTF8StringLength); - i += _name.UTF8StringLength; - - /* xmlns if necessary */ - if (prefix == nil && ((_namespace != nil && - ![_namespace isEqual: defaultNS]) || - (_namespace == nil && defaultNS != nil))) { - length += _namespace.UTF8StringLength + 9; - @try { - cString = [self resizeMemory: cString - size: length]; - } @catch (id e) { - [self freeMemory: cString]; - @throw e; - } - - memcpy(cString + i, " xmlns='", 8); - i += 8; - memcpy(cString + i, _namespace.UTF8String, - _namespace.UTF8StringLength); - i += _namespace.UTF8StringLength; - cString[i++] = '\''; - } - - /* Attributes */ - for (OFXMLAttribute *attribute in _attributes) { - void *pool2 = objc_autoreleasePoolPush(); - const char *attributeNameCString = attribute->_name.UTF8String; - size_t attributeNameLength = attribute->_name.UTF8StringLength; - OFString *attributePrefix = nil; - OFString *tmp = attribute.stringValue.stringByXMLEscaping; - char delimiter = (attribute->_useDoubleQuotes ? '"' : '\''); - - if (attribute->_namespace != nil && - (attributePrefix = [allNamespaces objectForKey: - attribute->_namespace]) == nil) - @throw [OFUnboundNamespaceException - exceptionWithNamespace: [attribute namespace] - element: self]; - - length += attributeNameLength + (attributePrefix != nil - ? attributePrefix.UTF8StringLength + 1 : 0) + - tmp.UTF8StringLength + 4; - - @try { - cString = [self resizeMemory: cString - size: length]; - } @catch (id e) { - [self freeMemory: cString]; - @throw e; - } - - cString[i++] = ' '; - if (attributePrefix != nil) { - memcpy(cString + i, attributePrefix.UTF8String, - attributePrefix.UTF8StringLength); - i += attributePrefix.UTF8StringLength; - cString[i++] = ':'; - } - memcpy(cString + i, attributeNameCString, attributeNameLength); - i += attributeNameLength; - cString[i++] = '='; - cString[i++] = delimiter; - memcpy(cString + i, tmp.UTF8String, tmp.UTF8StringLength); - i += tmp.UTF8StringLength; - cString[i++] = delimiter; - - objc_autoreleasePoolPop(pool2); - } - - /* Children */ - if (_children != nil) { - OFMutableData *tmp = [OFMutableData data]; - bool indent; - - if (indentation > 0) { - indent = true; - - for (OFXMLNode *child in _children) { - if ([child isKindOfClass: charactersClass] || - [child isKindOfClass: CDATAClass]) { - indent = false; - break; - } - } - } else - indent = false; - - for (OFXMLNode *child in _children) { - OFString *childString; - unsigned int ind = (indent ? indentation : 0); - - if (ind) - [tmp addItem: "\n"]; - - if ([child isKindOfClass: [OFXMLElement class]]) - childString = [(OFXMLElement *)child - of_XMLStringWithParent: self - namespaces: allNamespaces - indentation: ind - level: level + 1]; - else - childString = [child - XMLStringWithIndentation: ind - level: level + 1]; - - [tmp addItems: childString.UTF8String - count: childString.UTF8StringLength]; - } - - if (indent) - [tmp addItem: "\n"]; - - length += tmp.count + _name.UTF8StringLength + 2 + - (indent ? level * indentation : 0); - @try { - cString = [self resizeMemory: cString - size: length]; - } @catch (id e) { - [self freeMemory: cString]; - @throw e; - } - - cString[i++] = '>'; - - memcpy(cString + i, tmp.items, tmp.count); - i += tmp.count; - - if (indent) { - memset(cString + i, ' ', level * indentation); - i += level * indentation; - } - - cString[i++] = '<'; - cString[i++] = '/'; - if (prefix != nil) { - length += prefix.UTF8StringLength + 1; - @try { - cString = [self resizeMemory: cString - size: length]; - } @catch (id e) { - [self freeMemory: cString]; - @throw e; - } + cString = of_malloc(length, 1); + + @try { + memset(cString + i, ' ', level * indentation); + i += level * indentation; + + /* Start of tag */ + cString[i++] = '<'; + + if (prefix != nil && ![_namespace isEqual: defaultNS]) { + length += prefix.UTF8StringLength + 1; + cString = of_realloc(cString, length, 1); memcpy(cString + i, prefix.UTF8String, prefix.UTF8StringLength); i += prefix.UTF8StringLength; cString[i++] = ':'; } + memcpy(cString + i, _name.UTF8String, _name.UTF8StringLength); i += _name.UTF8StringLength; - } else - cString[i++] = '/'; - - cString[i++] = '>'; - assert(i == length); - - objc_autoreleasePoolPop(pool); - - @try { + + /* xmlns if necessary */ + if (prefix == nil && ((_namespace != nil && + ![_namespace isEqual: defaultNS]) || + (_namespace == nil && defaultNS != nil))) { + length += _namespace.UTF8StringLength + 9; + cString = of_realloc(cString, length, 1); + + memcpy(cString + i, " xmlns='", 8); + i += 8; + memcpy(cString + i, _namespace.UTF8String, + _namespace.UTF8StringLength); + i += _namespace.UTF8StringLength; + cString[i++] = '\''; + } + + /* Attributes */ + for (OFXMLAttribute *attribute in _attributes) { + void *pool2 = objc_autoreleasePoolPush(); + const char *attributeNameCString = + attribute->_name.UTF8String; + size_t attributeNameLength = + attribute->_name.UTF8StringLength; + OFString *attributePrefix = nil; + OFString *tmp = + attribute.stringValue.stringByXMLEscaping; + char delimiter = (attribute->_useDoubleQuotes + ? '"' : '\''); + + if (attribute->_namespace != nil && + (attributePrefix = [allNS objectForKey: + attribute->_namespace]) == nil) + @throw [OFUnboundNamespaceException + exceptionWithNamespace: attribute.namespace + element: self]; + + length += attributeNameLength + (attributePrefix != nil + ? attributePrefix.UTF8StringLength + 1 : 0) + + tmp.UTF8StringLength + 4; + cString = of_realloc(cString, length, 1); + + cString[i++] = ' '; + if (attributePrefix != nil) { + memcpy(cString + i, attributePrefix.UTF8String, + attributePrefix.UTF8StringLength); + i += attributePrefix.UTF8StringLength; + cString[i++] = ':'; + } + memcpy(cString + i, attributeNameCString, + attributeNameLength); + i += attributeNameLength; + cString[i++] = '='; + cString[i++] = delimiter; + memcpy(cString + i, tmp.UTF8String, + tmp.UTF8StringLength); + i += tmp.UTF8StringLength; + cString[i++] = delimiter; + + objc_autoreleasePoolPop(pool2); + } + + /* Children */ + if (_children != nil) { + OFMutableData *tmp = [OFMutableData data]; + bool indent; + + if (indentation > 0) { + indent = true; + + for (OFXMLNode *child in _children) { + if ([child isKindOfClass: + [OFXMLCharacters class]] || + [child isKindOfClass: + [OFXMLCDATA class]]) { + indent = false; + break; + } + } + } else + indent = false; + + for (OFXMLNode *child in _children) { + OFString *childString; + unsigned int ind = (indent ? indentation : 0); + + if (ind) + [tmp addItem: "\n"]; + + if ([child isKindOfClass: [OFXMLElement class]]) + childString = [(OFXMLElement *)child + of_XMLStringWithParent: self + namespaces: allNS + indentation: ind + level: level + 1]; + else + childString = [child + XMLStringWithIndentation: ind + level: level + + 1]; + + [tmp addItems: childString.UTF8String + count: childString.UTF8StringLength]; + } + + if (indent) + [tmp addItem: "\n"]; + + length += tmp.count + _name.UTF8StringLength + 2 + + (indent ? level * indentation : 0); + cString = of_realloc(cString, length, 1); + + cString[i++] = '>'; + + memcpy(cString + i, tmp.items, tmp.count); + i += tmp.count; + + if (indent) { + memset(cString + i, ' ', level * indentation); + i += level * indentation; + } + + cString[i++] = '<'; + cString[i++] = '/'; + if (prefix != nil) { + length += prefix.UTF8StringLength + 1; + cString = of_realloc(cString, length, 1); + + memcpy(cString + i, prefix.UTF8String, + prefix.UTF8StringLength); + i += prefix.UTF8StringLength; + cString[i++] = ':'; + } + memcpy(cString + i, _name.UTF8String, + _name.UTF8StringLength); + i += _name.UTF8StringLength; + } else + cString[i++] = '/'; + + cString[i++] = '>'; + assert(i == length); + + objc_autoreleasePoolPop(pool); + ret = [OFString stringWithUTF8String: cString length: length]; } @finally { - [self freeMemory: cString]; + free(cString); } return ret; } - (OFString *)XMLString