Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Updated KissXML source to 5.0 to fix #85

  • Loading branch information...
commit 7ed52f2f31210b2f87a854d68f4ad61500e83116 1 parent b4635b7
Mark Hewett authored April 21, 2012 John Flanagan committed April 21, 2012
1  KeePassLib/Kdb4Node.h
@@ -9,6 +9,7 @@
9 9
 #import <Foundation/Foundation.h>
10 10
 #import "Kdb.h"
11 11
 #import "DDXML.h"
  12
+#import "DDXMLElementAdditions.h"
12 13
 
13 14
 #define KDB4_PRE_SIG1 (0x9AA2D903)
14 15
 #define KDB4_PRE_SIG2 (0xB54BFB66)
17  KeePassLib/Kdb4Node.m
@@ -8,6 +8,23 @@
8 8
 
9 9
 #import "Kdb4Node.h"
10 10
 
  11
+@implementation DDXMLElement (MKPAdditions)
  12
+
  13
+- (void)removeChild:(DDXMLNode *)child {
  14
+    int idx = -1;
  15
+    for (int i = 0; i < [self childCount]; i++) {
  16
+        if ([self childAtIndex:i] == child) {
  17
+            idx = i;
  18
+            break;
  19
+        }
  20
+    }
  21
+    if (idx >= 0) {
  22
+        [self removeChildAtIndex:idx];
  23
+    }
  24
+}
  25
+
  26
+@end
  27
+
11 28
 @implementation Kdb4Group
12 29
 
13 30
 @synthesize element;
24  KeePassLib/Kdb4Parser.m
@@ -19,6 +19,30 @@
19 19
 #import "Kdb4Node.h"
20 20
 #import "Base64.h"
21 21
 
  22
+@implementation DDXMLDocument (MKPDDXMLDocument_Additions)
  23
+
  24
+- (id)initWithReadIO:(xmlInputReadCallback)ioread closeIO:(xmlInputCloseCallback)ioclose context:(void*)ioctx options:(NSUInteger)mask error:(NSError **)error {
  25
+	
  26
+	// Even though xmlKeepBlanksDefault(0) is called in DDXMLNode's initialize method,
  27
+	// it has been documented that this call seems to get reset on the iPhone:
  28
+	// http://code.google.com/p/kissxml/issues/detail?id=8
  29
+	// 
  30
+	// Therefore, we call it again here just to be safe.
  31
+	xmlKeepBlanksDefault(0);
  32
+	
  33
+	xmlDocPtr doc = xmlReadIO(ioread, ioclose, ioctx, NULL, NULL, mask);
  34
+	if (doc == NULL)
  35
+	{
  36
+		if (error) *error = [NSError errorWithDomain:@"DDXMLErrorDomain" code:1 userInfo:nil];
  37
+		
  38
+		return nil;
  39
+	}
  40
+	
  41
+	return [self initWithDocPrimitive:doc owner:nil];
  42
+}
  43
+
  44
+@end
  45
+
22 46
 @interface Kdb4Parser (PrivateMethods)
23 47
 - (void)decodeProtected:(DDXMLElement*)root;
24 48
 - (Kdb4Group*)parseGroup:(DDXMLElement*)root;
8  KeePassLib/Kdb4Writer.m
@@ -146,12 +146,8 @@ - (void)writeHeader:(OutputStream*)outputStream {
146 146
 }
147 147
 
148 148
 - (void)newFile:(NSString*)fileName withPassword:(KdbPassword*)kdbPassword {
149  
-    DDXMLElement *docRoot = [DDXMLNode elementWithName:@"KeePassFile"];
150  
-    
151  
-    DDXMLElement *rootElement = [DDXMLElement elementWithName:@"Root"];
152  
-    [docRoot addChild:rootElement];
153  
-    
154  
-    DDXMLDocument *document = [[DDXMLDocument alloc] initWithRootElement:docRoot];
  149
+    DDXMLDocument *document = [[DDXMLDocument alloc] initWithXMLString:@"<KeePassFile><Root></Root></KeePassFile>" options:0 error:nil];
  150
+    DDXMLElement *rootElement = [[document rootElement] elementForName:@"Root"];
155 151
     Kdb4Tree *tree = [[Kdb4Tree alloc] initWithDocument:document];
156 152
     [document release];
157 153
     
1  KeePassLib/KdbPassword.m
@@ -11,6 +11,7 @@
11 11
 
12 12
 #import "KdbPassword.h"
13 13
 #import "DDXML.h"
  14
+#import "DDXMLElementAdditions.h"
14 15
 #import "Base64.h"
15 16
 
16 17
 @interface KdbPassword (PrivateMethods)
3  KissXML/Additions/DDXMLElementAdditions.h
@@ -14,6 +14,9 @@
14 14
 - (NSString *)xmlns;
15 15
 - (void)setXmlns:(NSString *)ns;
16 16
 
  17
+- (NSString *)prettyXMLString;
  18
+- (NSString *)compactXMLString;
  19
+
17 20
 - (void)addAttributeWithName:(NSString *)name stringValue:(NSString *)string;
18 21
 
19 22
 - (NSDictionary *)attributesAsDictionary;
16  KissXML/Additions/DDXMLElementAdditions.m
@@ -87,6 +87,22 @@ - (void)setXmlns:(NSString *)ns
87 87
 }
88 88
 
89 89
 /**
  90
+ * Shortcut to get a pretty (formatted) string representation of the element.
  91
+**/
  92
+- (NSString *)prettyXMLString
  93
+{
  94
+	return [self XMLStringWithOptions:(DDXMLNodePrettyPrint | DDXMLNodeCompactEmptyElement)];
  95
+}
  96
+
  97
+/**
  98
+ * Shortcut to get a compact string representation of the element.
  99
+**/
  100
+- (NSString *)compactXMLString
  101
+{
  102
+    return [self XMLStringWithOptions:DDXMLNodeCompactEmptyElement];
  103
+}
  104
+
  105
+/**
90 106
  *	Shortcut to avoid having to manually create a DDXMLNode everytime.
91 107
 **/
92 108
 - (void)addAttributeWithName:(NSString *)name stringValue:(NSString *)string
8  KissXML/Categories/NSString+DDXML.m
... ...
@@ -1,5 +1,8 @@
1 1
 #import "NSString+DDXML.h"
2 2
 
  3
+#if ! __has_feature(objc_arc)
  4
+#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  5
+#endif
3 6
 
4 7
 @implementation NSString (DDXML)
5 8
 
@@ -17,12 +20,11 @@ - (NSString *)stringByTrimming
17 20
 - (NSString *)stringByTrimming
18 21
 {
19 22
 	NSMutableString *mStr = [self mutableCopy];
20  
-	CFStringTrimWhitespace((CFMutableStringRef)mStr);
  23
+	CFStringTrimWhitespace((__bridge CFMutableStringRef)mStr);
21 24
 	
22 25
 	NSString *result = [mStr copy];
23 26
 	
24  
-	[mStr release];
25  
-	return [result autorelease];
  27
+	return result;
26 28
 }
27 29
 #endif
28 30
 
194  KissXML/DDXML.h
... ...
@@ -1,4 +1,196 @@
  1
+/**
  2
+ * Welcome to KissXML.
  3
+ * 
  4
+ * The project page has documentation if you have questions.
  5
+ * https://github.com/robbiehanson/KissXML
  6
+ * 
  7
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
  8
+ * https://github.com/robbiehanson/KissXML/wiki/GettingStarted
  9
+ * 
  10
+ * KissXML provides a drop-in replacement for Apple's NSXML class cluster.
  11
+ * The goal is to get the exact same behavior as the NSXML classes.
  12
+ * 
  13
+ * For API Reference, see Apple's excellent documentation,
  14
+ * either via Xcode's Mac OS X documentation, or via the web:
  15
+ * 
  16
+ * https://github.com/robbiehanson/KissXML/wiki/Reference
  17
+**/
  18
+
1 19
 #import "DDXMLNode.h"
2 20
 #import "DDXMLElement.h"
3 21
 #import "DDXMLDocument.h"
4  
-#import "DDXMLElementAdditions.h"
  22
+
  23
+
  24
+
  25
+#if TARGET_OS_IPHONE && 0 // Disabled by default
  26
+
  27
+// Since KissXML is a drop in replacement for NSXML,
  28
+// it may be desireable (when writing cross-platform code to be used on both Mac OS X and iOS)
  29
+// to use the NSXML prefixes instead of the DDXML prefix.
  30
+// 
  31
+// This way, on Mac OS X it uses NSXML, and on iOS it uses KissXML.
  32
+
  33
+#ifndef NSXMLNode
  34
+  #define NSXMLNode DDXMLNode
  35
+#endif
  36
+#ifndef NSXMLElement
  37
+  #define NSXMLElement DDXMLElement
  38
+#endif
  39
+#ifndef NSXMLDocument
  40
+  #define NSXMLDocument DDXMLDocument
  41
+#endif
  42
+
  43
+#ifndef NSXMLInvalidKind
  44
+  #define NSXMLInvalidKind DDXMLInvalidKind
  45
+#endif
  46
+#ifndef NSXMLDocumentKind
  47
+  #define NSXMLDocumentKind DDXMLDocumentKind
  48
+#endif
  49
+#ifndef NSXMLElementKind
  50
+  #define NSXMLElementKind DDXMLElementKind
  51
+#endif
  52
+#ifndef NSXMLAttributeKind
  53
+  #define NSXMLAttributeKind DDXMLAttributeKind
  54
+#endif
  55
+#ifndef NSXMLNamespaceKind
  56
+  #define NSXMLNamespaceKind DDXMLNamespaceKind
  57
+#endif
  58
+#ifndef NSXMLProcessingInstructionKind
  59
+  #define NSXMLProcessingInstructionKind DDXMLProcessingInstructionKind
  60
+#endif
  61
+#ifndef NSXMLCommentKind
  62
+  #define NSXMLCommentKind DDXMLCommentKind
  63
+#endif
  64
+#ifndef NSXMLTextKind
  65
+  #define NSXMLTextKind DDXMLTextKind
  66
+#endif
  67
+#ifndef NSXMLDTDKind
  68
+  #define NSXMLDTDKind DDXMLDTDKind
  69
+#endif
  70
+#ifndef NSXMLEntityDeclarationKind
  71
+  #define NSXMLEntityDeclarationKind DDXMLEntityDeclarationKind
  72
+#endif
  73
+#ifndef NSXMLAttributeDeclarationKind
  74
+  #define NSXMLAttributeDeclarationKind DDXMLAttributeDeclarationKind
  75
+#endif
  76
+#ifndef NSXMLElementDeclarationKind
  77
+  #define NSXMLElementDeclarationKind DDXMLElementDeclarationKind
  78
+#endif
  79
+#ifndef NSXMLNotationDeclarationKind
  80
+  #define NSXMLNotationDeclarationKind DDXMLNotationDeclarationKind
  81
+#endif
  82
+
  83
+#ifndef NSXMLNodeOptionsNone
  84
+  #define NSXMLNodeOptionsNone DDXMLNodeOptionsNone
  85
+#endif
  86
+#ifndef NSXMLNodeExpandEmptyElement
  87
+  #define NSXMLNodeExpandEmptyElement DDXMLNodeExpandEmptyElement
  88
+#endif
  89
+#ifndef NSXMLNodeCompactEmptyElement
  90
+  #define NSXMLNodeCompactEmptyElement DDXMLNodeCompactEmptyElement
  91
+#endif
  92
+#ifndef NSXMLNodePrettyPrint
  93
+  #define NSXMLNodePrettyPrint DDXMLNodePrettyPrint
  94
+#endif
  95
+
  96
+#endif // #if TARGET_OS_IPHONE
  97
+
  98
+
  99
+
  100
+// KissXML has rather straight-forward memory management:
  101
+// https://github.com/robbiehanson/KissXML/wiki/MemoryManagementThreadSafety
  102
+// 
  103
+// There are 3 important concepts to keep in mind when working with KissXML:
  104
+// 
  105
+// 
  106
+// 1.) KissXML provides a light-weight wrapper around libxml.
  107
+// 
  108
+// The parsing, creation, storage, etc of the xml tree is all done via libxml.
  109
+// This is a fast low-level C library that's been around for ages, and comes pre-installed on Mac OS X and iOS.
  110
+// KissXML provides an easy-to-use Objective-C library atop libxml.
  111
+// So a DDXMLNode, DDXMLElement, or DDXMLDocument are simply objective-c objects
  112
+// with pointers to the underlying libxml C structure.
  113
+// Then only time you need to be aware of any of this is when it comes to equality.
  114
+// In order to maximize speed and provide read-access thread-safety,
  115
+// the library may create multiple DDXML wrapper objects that point to the same underlying xml node.
  116
+// So don't assume you can test for equality with "==".
  117
+// Instead use the isEqual method (as you should generally do with objects anyway).
  118
+// 
  119
+// 
  120
+// 2.) XML is implicitly a tree heirarchy, and the XML API's are designed to allow traversal up & down the tree.
  121
+// 
  122
+// The tree heirarchy and API contract have an implicit impact concerning memory management.
  123
+// 
  124
+// <starbucks>
  125
+//   <latte/>
  126
+// </starbucks>
  127
+// 
  128
+// Imagine you have a DDXMLNode corresponding to the starbucks node,
  129
+// and you have a DDXMLNode corresponding to the latte node.
  130
+// Now imagine you release the starbucks node, but you retain a reference to the latte node.
  131
+// What happens?
  132
+// Well the latte node is a part of the xml tree heirarchy.
  133
+// So if the latte node is still around, the xml tree heirarchy must stick around as well.
  134
+// So even though the DDXMLNode corresponding to the starbucks node may get deallocated,
  135
+// the underlying xml tree structure won't be freed until the latte node gets dealloacated.
  136
+// 
  137
+// In general, this means that KissXML remains thread-safe when reading and processing a tree.
  138
+// If you traverse a tree and fork off asynchronous tasks to process subnodes,
  139
+// the tree will remain properly in place until all your asynchronous tasks have completed.
  140
+// In other words, it just works.
  141
+// 
  142
+// However, if you parse a huge document into memory, and retain a single node from the giant xml tree...
  143
+// Well you should see the problem this creates.
  144
+// Instead, in this situation, copy or detach the node if you want to keep it around.
  145
+// Or just extract the info you need from it.
  146
+// 
  147
+// 
  148
+// 3.) KissXML is read-access thread-safe, but write-access thread-unsafe (designed for speed).
  149
+// 
  150
+// <starbucks>
  151
+//   <latte/>
  152
+// </starbucks>
  153
+// 
  154
+// Imagine you have a DDXMLNode corresponding to the starbucks node,
  155
+// and you have a DDXMLNode corresponding to the latte node.
  156
+// What happens if you invoke [starbucks removeChildAtIndex:0]?
  157
+// Well the undelying xml tree will remove the latte node, and release the associated memory.
  158
+// And what if you still have a reference to the DDXMLNode that corresponds to the latte node?
  159
+// Well the short answer is that you shouldn't use it. At all.
  160
+// This is pretty obvious when you think about it from the context of this simple example.
  161
+// But in the real world, you might have multiple threads running in parallel,
  162
+// and you might accidently modify a node while another thread is processing it.
  163
+// 
  164
+// To completely fix this problem, and provide write-access thread-safety, would require extensive overhead.
  165
+// This overhead is completely unwanted in the majority of cases.
  166
+// Most XML usage patterns are heavily read-only.
  167
+// And in the case of xml creation or modification, it is generally done on the same thread.
  168
+// Thus the KissXML library is write-access thread-unsafe, but provides speedier performance.
  169
+// 
  170
+// However, when such a bug does creep up, it produces horrible side-effects.
  171
+// Essentially the pointer to the underlying xml structure becomes a dangling pointer,
  172
+// which means that accessing the dangling pointer might give you the correct results, or completely random results.
  173
+// And attempting to make modifications to non-existant xml nodes via the dangling pointer might do nothing,
  174
+// or completely corrupt your heap and cause un-explainable crashes in random parts of your library.
  175
+// Heap corruption is one of the worst problems to track down.
  176
+// So to help out, the library provides a debugging macro to track down these problems.
  177
+// That is, if you invalidate the write-access thread-unsafe rule,
  178
+// this macro will tell you when you're trying to access a now-dangling pointer.
  179
+// 
  180
+// How does it work?
  181
+// Well everytime a DDXML wrapper object is created atop a libxml structure,
  182
+// it marks the linkage in a table.
  183
+// And everytime a libxml structure is freed, it destorys all corresponding linkages in the table.
  184
+// So everytime a DDXML wrapper objects is about to dereference it's pointer,
  185
+// it first ensures the linkage still exists in the table.
  186
+// 
  187
+// Set to 1 to enable
  188
+// Set to 0 to disable (this is the default)
  189
+// 
  190
+// The debugging macro adds a significant amount of overhead, and should NOT be enabled on production builds.
  191
+
  192
+#if DEBUG
  193
+  #define DDXML_DEBUG_MEMORY_ISSUES 0
  194
+#else
  195
+  #define DDXML_DEBUG_MEMORY_ISSUES 0 // Don't change me!
  196
+#endif
31  KissXML/DDXMLDocument.h
@@ -2,6 +2,23 @@
2 2
 #import "DDXMLElement.h"
3 3
 #import "DDXMLNode.h"
4 4
 
  5
+/**
  6
+ * Welcome to KissXML.
  7
+ * 
  8
+ * The project page has documentation if you have questions.
  9
+ * https://github.com/robbiehanson/KissXML
  10
+ * 
  11
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
  12
+ * https://github.com/robbiehanson/KissXML/wiki/GettingStarted
  13
+ * 
  14
+ * KissXML provides a drop-in replacement for Apple's NSXML class cluster.
  15
+ * The goal is to get the exact same behavior as the NSXML classes.
  16
+ * 
  17
+ * For API Reference, see Apple's excellent documentation,
  18
+ * either via Xcode's Mac OS X documentation, or via the web:
  19
+ * 
  20
+ * https://github.com/robbiehanson/KissXML/wiki/Reference
  21
+**/
5 22
 
6 23
 enum {
7 24
 	DDXMLDocumentXMLKind = 0,
@@ -14,23 +31,23 @@ typedef NSUInteger DDXMLDocumentContentKind;
14 31
 @interface DDXMLDocument : DDXMLNode
15 32
 {
16 33
 }
  34
+- (id)initWithDocPrimitive:(xmlDocPtr)doc owner:(DDXMLNode *)inOwner;
17 35
 
18 36
 - (id)initWithXMLString:(NSString *)string options:(NSUInteger)mask error:(NSError **)error;
19 37
 //- (id)initWithContentsOfURL:(NSURL *)url options:(NSUInteger)mask error:(NSError **)error;
20 38
 - (id)initWithData:(NSData *)data options:(NSUInteger)mask error:(NSError **)error;
21  
-- (id)initWithReadIO:(xmlInputReadCallback)ioread closeIO:(xmlInputCloseCallback)ioclose context:(void*)ioctx options:(NSUInteger)mask error:(NSError **)error;
22  
-- (id)initWithRootElement:(DDXMLElement *)element;
  39
+//- (id)initWithRootElement:(DDXMLElement *)element;
23 40
 
24 41
 //+ (Class)replacementClassForClass:(Class)cls;
25 42
 
26 43
 //- (void)setCharacterEncoding:(NSString *)encoding; //primitive
27 44
 //- (NSString *)characterEncoding; //primitive
28 45
 
29  
-- (void)setVersion:(NSString *)version;
30  
-- (NSString *)version;
  46
+//- (void)setVersion:(NSString *)version;
  47
+//- (NSString *)version;
31 48
 
32  
-- (void)setStandalone:(BOOL)standalone;
33  
-- (BOOL)isStandalone;
  49
+//- (void)setStandalone:(BOOL)standalone;
  50
+//- (BOOL)isStandalone;
34 51
 
35 52
 //- (void)setDocumentContentKind:(DDXMLDocumentContentKind)kind;
36 53
 //- (DDXMLDocumentContentKind)documentContentKind;
@@ -41,7 +58,7 @@ typedef NSUInteger DDXMLDocumentContentKind;
41 58
 //- (void)setDTD:(DDXMLDTD *)documentTypeDeclaration;
42 59
 //- (DDXMLDTD *)DTD;
43 60
 
44  
-- (void)setRootElement:(DDXMLNode *)root;
  61
+//- (void)setRootElement:(DDXMLNode *)root;
45 62
 - (DDXMLElement *)rootElement;
46 63
 
47 64
 //- (void)insertChild:(DDXMLNode *)child atIndex:(NSUInteger)index;
109  KissXML/DDXMLDocument.m
... ...
@@ -1,6 +1,27 @@
1 1
 #import "DDXMLPrivate.h"
2 2
 #import "NSString+DDXML.h"
3 3
 
  4
+#if ! __has_feature(objc_arc)
  5
+#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  6
+#endif
  7
+
  8
+/**
  9
+ * Welcome to KissXML.
  10
+ * 
  11
+ * The project page has documentation if you have questions.
  12
+ * https://github.com/robbiehanson/KissXML
  13
+ * 
  14
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
  15
+ * https://github.com/robbiehanson/KissXML/wiki/GettingStarted
  16
+ * 
  17
+ * KissXML provides a drop-in replacement for Apple's NSXML class cluster.
  18
+ * The goal is to get the exact same behavior as the NSXML classes.
  19
+ * 
  20
+ * For API Reference, see Apple's excellent documentation,
  21
+ * either via Xcode's Mac OS X documentation, or via the web:
  22
+ * 
  23
+ * https://github.com/robbiehanson/KissXML/wiki/Reference
  24
+**/
4 25
 
5 26
 @implementation DDXMLDocument
6 27
 
@@ -8,31 +29,30 @@ @implementation DDXMLDocument
8 29
  * Returns a DDXML wrapper object for the given primitive node.
9 30
  * The given node MUST be non-NULL and of the proper type.
10 31
 **/
11  
-+ (id)nodeWithDocPrimitive:(xmlDocPtr)doc freeOnDealloc:(BOOL)flag
  32
++ (id)nodeWithDocPrimitive:(xmlDocPtr)doc owner:(DDXMLNode *)owner
12 33
 {
13  
-	return [[[DDXMLDocument alloc] initWithDocPrimitive:doc freeOnDealloc:flag] autorelease];
  34
+	return [[DDXMLDocument alloc] initWithDocPrimitive:doc owner:owner];
14 35
 }
15 36
 
16  
-- (id)initWithDocPrimitive:(xmlDocPtr)doc freeOnDealloc:(BOOL)flag
  37
+- (id)initWithDocPrimitive:(xmlDocPtr)doc owner:(DDXMLNode *)inOwner
17 38
 {
18  
-	self = [super initWithPrimitive:(xmlKindPtr)doc freeOnDealloc:flag];
  39
+	self = [super initWithPrimitive:(xmlKindPtr)doc owner:inOwner];
19 40
 	return self;
20 41
 }
21 42
 
22  
-+ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
  43
++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner
23 44
 {
24 45
 	// Promote initializers which use proper parameter types to enable compiler to catch more mistakes
25  
-	NSAssert(NO, @"Use nodeWithDocPrimitive:freeOnDealloc:");
  46
+	NSAssert(NO, @"Use nodeWithDocPrimitive:owner:");
26 47
 	
27 48
 	return nil;
28 49
 }
29 50
 
30  
-- (id)initWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
  51
+- (id)initWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)inOwner
31 52
 {
32 53
 	// Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
33  
-	NSAssert(NO, @"Use initWithDocPrimitive:freeOnDealloc:");
  54
+	NSAssert(NO, @"Use initWithDocPrimitive:owner:");
34 55
 	
35  
-	[self release];
36 56
 	return nil;
37 57
 }
38 58
 
@@ -61,7 +81,6 @@ - (id)initWithData:(NSData *)data options:(NSUInteger)mask error:(NSError **)err
61 81
 	{
62 82
 		if (error) *error = [NSError errorWithDomain:@"DDXMLErrorDomain" code:0 userInfo:nil];
63 83
 		
64  
-		[self release];
65 84
 		return nil;
66 85
 	}
67 86
 	
@@ -77,63 +96,10 @@ - (id)initWithData:(NSData *)data options:(NSUInteger)mask error:(NSError **)err
77 96
 	{
78 97
 		if (error) *error = [NSError errorWithDomain:@"DDXMLErrorDomain" code:1 userInfo:nil];
79 98
 		
80  
-		[self release];
81  
-		return nil;
82  
-	}
83  
-	
84  
-	return [self initWithDocPrimitive:doc freeOnDealloc:YES];
85  
-}
86  
-
87  
-- (id)initWithReadIO:(xmlInputReadCallback)ioread closeIO:(xmlInputCloseCallback)ioclose context:(void*)ioctx options:(NSUInteger)mask error:(NSError **)error {
88  
-	
89  
-	// Even though xmlKeepBlanksDefault(0) is called in DDXMLNode's initialize method,
90  
-	// it has been documented that this call seems to get reset on the iPhone:
91  
-	// http://code.google.com/p/kissxml/issues/detail?id=8
92  
-	// 
93  
-	// Therefore, we call it again here just to be safe.
94  
-	xmlKeepBlanksDefault(0);
95  
-	
96  
-	xmlDocPtr doc = xmlReadIO(ioread, ioclose, ioctx, NULL, NULL, mask);
97  
-	if (doc == NULL)
98  
-	{
99  
-		if (error) *error = [NSError errorWithDomain:@"DDXMLErrorDomain" code:1 userInfo:nil];
100  
-		
101 99
 		return nil;
102 100
 	}
103 101
 	
104  
-	return [self initWithDocPrimitive:doc freeOnDealloc:YES];
105  
-}
106  
-
107  
-- (id)initWithRootElement:(DDXMLElement *)element {
108  
-    xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
109  
-    if (self = [self initWithDocPrimitive:doc freeOnDealloc:YES]) {
110  
-        if (element) {
111  
-            [self setRootElement:element];
112  
-        }
113  
-    }
114  
-    
115  
-    return self;
116  
-}
117  
-
118  
-- (void)setVersion:(NSString *)version {
119  
-    xmlDocPtr doc = (xmlDocPtr)genericPtr;
120  
-    xmlFree((xmlChar *)doc->version);
121  
-    doc->version = xmlStrdup([version xmlChar]);
122  
-}
123  
-
124  
-- (NSString *)version {
125  
-    xmlDocPtr doc = (xmlDocPtr)genericPtr;
126  
-    return [NSString stringWithUTF8String:((const char*)doc->version)];
127  
-}
128  
-
129  
-- (void)setStandalone:(BOOL)standalone {
130  
-    xmlDocPtr doc = (xmlDocPtr)genericPtr;
131  
-    doc->standalone = standalone;
132  
-}
133  
-
134  
-- (BOOL)isStandalone {
135  
-    xmlDocPtr doc = (xmlDocPtr)genericPtr;
136  
-    return doc->standalone;
  102
+	return [self initWithDocPrimitive:doc owner:nil];
137 103
 }
138 104
 
139 105
 /**
@@ -141,6 +107,10 @@ - (BOOL)isStandalone {
141 107
 **/
142 108
 - (DDXMLElement *)rootElement
143 109
 {
  110
+#if DDXML_DEBUG_MEMORY_ISSUES
  111
+	DDXMLNotZombieAssert();
  112
+#endif
  113
+	
144 114
 	xmlDocPtr doc = (xmlDocPtr)genericPtr;
145 115
 	
146 116
 	// doc->children is a list containing possibly comments, DTDs, etc...
@@ -148,23 +118,22 @@ - (DDXMLElement *)rootElement
148 118
 	xmlNodePtr rootNode = xmlDocGetRootElement(doc);
149 119
 	
150 120
 	if (rootNode != NULL)
151  
-		return [DDXMLElement nodeWithElementPrimitive:rootNode freeOnDealloc:NO];
  121
+		return [DDXMLElement nodeWithElementPrimitive:rootNode owner:self];
152 122
 	else
153 123
 		return nil;
154 124
 }
155 125
 
156  
-- (void)setRootElement:(DDXMLNode *)root {
157  
-    xmlDocPtr doc = (xmlDocPtr)genericPtr;
158  
-    xmlDocSetRootElement(doc, (xmlNodePtr)root->genericPtr);
159  
-}
160  
-
161 126
 - (NSData *)XMLData
162 127
 {
  128
+	// Zombie test occurs in XMLString
  129
+	
163 130
 	return [[self XMLString] dataUsingEncoding:NSUTF8StringEncoding];
164 131
 }
165 132
 
166 133
 - (NSData *)XMLDataWithOptions:(NSUInteger)options
167 134
 {
  135
+	// Zombie test occurs in XMLString
  136
+	
168 137
 	return [[self XMLStringWithOptions:options] dataUsingEncoding:NSUTF8StringEncoding];
169 138
 }
170 139
 
18  KissXML/DDXMLElement.h
... ...
@@ -1,6 +1,23 @@
1 1
 #import <Foundation/Foundation.h>
2 2
 #import "DDXMLNode.h"
3 3
 
  4
+/**
  5
+ * Welcome to KissXML.
  6
+ * 
  7
+ * The project page has documentation if you have questions.
  8
+ * https://github.com/robbiehanson/KissXML
  9
+ * 
  10
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
  11
+ * https://github.com/robbiehanson/KissXML/wiki/GettingStarted
  12
+ * 
  13
+ * KissXML provides a drop-in replacement for Apple's NSXML class cluster.
  14
+ * The goal is to get the exact same behavior as the NSXML classes.
  15
+ * 
  16
+ * For API Reference, see Apple's excellent documentation,
  17
+ * either via Xcode's Mac OS X documentation, or via the web:
  18
+ * 
  19
+ * https://github.com/robbiehanson/KissXML/wiki/Reference
  20
+**/
4 21
 
5 22
 @interface DDXMLElement : DDXMLNode
6 23
 {
@@ -41,7 +58,6 @@
41 58
 - (void)insertChild:(DDXMLNode *)child atIndex:(NSUInteger)index;
42 59
 //- (void)insertChildren:(NSArray *)children atIndex:(NSUInteger)index;
43 60
 - (void)removeChildAtIndex:(NSUInteger)index;
44  
-- (void)removeChild:(DDXMLNode*)child;
45 61
 - (void)setChildren:(NSArray *)children;
46 62
 - (void)addChild:(DDXMLNode *)child;
47 63
 //- (void)replaceChildAtIndex:(NSUInteger)index withNode:(DDXMLNode *)node;
541  KissXML/DDXMLElement.m
... ...
@@ -1,6 +1,27 @@
1 1
 #import "DDXMLPrivate.h"
2 2
 #import "NSString+DDXML.h"
3 3
 
  4
+#if ! __has_feature(objc_arc)
  5
+#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  6
+#endif
  7
+
  8
+/**
  9
+ * Welcome to KissXML.
  10
+ * 
  11
+ * The project page has documentation if you have questions.
  12
+ * https://github.com/robbiehanson/KissXML
  13
+ * 
  14
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
  15
+ * https://github.com/robbiehanson/KissXML/wiki/GettingStarted
  16
+ * 
  17
+ * KissXML provides a drop-in replacement for Apple's NSXML class cluster.
  18
+ * The goal is to get the exact same behavior as the NSXML classes.
  19
+ * 
  20
+ * For API Reference, see Apple's excellent documentation,
  21
+ * either via Xcode's Mac OS X documentation, or via the web:
  22
+ * 
  23
+ * https://github.com/robbiehanson/KissXML/wiki/Reference
  24
+**/
4 25
 
5 26
 @implementation DDXMLElement
6 27
 
@@ -8,31 +29,30 @@ @implementation DDXMLElement
8 29
  * Returns a DDXML wrapper object for the given primitive node.
9 30
  * The given node MUST be non-NULL and of the proper type.
10 31
 **/
11  
-+ (id)nodeWithElementPrimitive:(xmlNodePtr)node freeOnDealloc:(BOOL)flag
  32
++ (id)nodeWithElementPrimitive:(xmlNodePtr)node owner:(DDXMLNode *)owner
12 33
 {
13  
-	return [[[DDXMLElement alloc] initWithElementPrimitive:node freeOnDealloc:flag] autorelease];
  34
+	return [[DDXMLElement alloc] initWithElementPrimitive:node owner:owner];
14 35
 }
15 36
 
16  
-- (id)initWithElementPrimitive:(xmlNodePtr)node freeOnDealloc:(BOOL)flag
  37
+- (id)initWithElementPrimitive:(xmlNodePtr)node owner:(DDXMLNode *)inOwner
17 38
 {
18  
-	self = [super initWithPrimitive:(xmlKindPtr)node freeOnDealloc:flag];
  39
+	self = [super initWithPrimitive:(xmlKindPtr)node owner:inOwner];
19 40
 	return self;
20 41
 }
21 42
 
22  
-+ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
  43
++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner
23 44
 {
24 45
 	// Promote initializers which use proper parameter types to enable compiler to catch more mistakes
25  
-	NSAssert(NO, @"Use nodeWithElementPrimitive:freeOnDealloc:");
  46
+	NSAssert(NO, @"Use nodeWithElementPrimitive:owner:");
26 47
 	
27 48
 	return nil;
28 49
 }
29 50
 
30  
-- (id)initWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
  51
+- (id)initWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)inOwner
31 52
 {
32 53
 	// Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
33  
-	NSAssert(NO, @"Use initWithElementPrimitive:freeOnDealloc:");
  54
+	NSAssert(NO, @"Use initWithElementPrimitive:owner:");
34 55
 	
35  
-	[self release];
36 56
 	return nil;
37 57
 }
38 58
 
@@ -43,11 +63,10 @@ - (id)initWithName:(NSString *)name
43 63
 	xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
44 64
 	if (node == NULL)
45 65
 	{
46  
-		[self release];
47 66
 		return nil;
48 67
 	}
49 68
 	
50  
-	return [self initWithElementPrimitive:node freeOnDealloc:YES];
  69
+	return [self initWithElementPrimitive:node owner:nil];
51 70
 }
52 71
 
53 72
 - (id)initWithName:(NSString *)name URI:(NSString *)URI
@@ -57,11 +76,10 @@ - (id)initWithName:(NSString *)name URI:(NSString *)URI
57 76
 	xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
58 77
 	if (node == NULL)
59 78
 	{
60  
-		[self release];
61 79
 		return nil;
62 80
 	}
63 81
 	
64  
-	DDXMLElement *result = [self initWithElementPrimitive:node freeOnDealloc:YES];
  82
+	DDXMLElement *result = [self initWithElementPrimitive:node owner:nil];
65 83
 	[result setURI:URI];
66 84
 	
67 85
 	return result;
@@ -74,11 +92,10 @@ - (id)initWithName:(NSString *)name stringValue:(NSString *)string
74 92
 	xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
75 93
 	if (node == NULL)
76 94
 	{
77  
-		[self release];
78 95
 		return nil;
79 96
 	}
80 97
 	
81  
-	DDXMLElement *result = [self initWithElementPrimitive:node freeOnDealloc:YES];
  98
+	DDXMLElement *result = [self initWithElementPrimitive:node owner:nil];
82 99
 	[result setStringValue:string];
83 100
 	
84 101
 	return result;
@@ -89,16 +106,13 @@ - (id)initWithXMLString:(NSString *)string error:(NSError **)error
89 106
 	DDXMLDocument *doc = [[DDXMLDocument alloc] initWithXMLString:string options:0 error:error];
90 107
 	if (doc == nil)
91 108
 	{
92  
-		[self release];
93 109
 		return nil;
94 110
 	}
95 111
 	
96 112
 	DDXMLElement *result = [doc rootElement];
97 113
 	[result detach];
98  
-	[doc release];
99 114
 	
100  
-	[self release];
101  
-	return [result retain];
  115
+	return result;
102 116
 }
103 117
 
104 118
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -106,6 +120,71 @@ - (id)initWithXMLString:(NSString *)string error:(NSError **)error
106 120
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
107 121
 
108 122
 /**
  123
+ * Helper method elementsForName and elementsForLocalName:URI: so work isn't duplicated.
  124
+ * The name parameter is required, all others are optional.
  125
+**/
  126
+- (NSArray *)_elementsForName:(NSString *)name
  127
+                    localName:(NSString *)localName
  128
+                       prefix:(NSString *)prefix
  129
+                          uri:(NSString *)uri
  130
+{
  131
+	// This is a private/internal method
  132
+	
  133
+	// Rule : !uri             => match: name
  134
+	// Rule : uri && hasPrefix => match: name || (localName && uri)
  135
+	// Rule : uri && !hasPefix => match: name && uri
  136
+	
  137
+	xmlNodePtr node = (xmlNodePtr)genericPtr;
  138
+	
  139
+	NSMutableArray *result = [NSMutableArray array];
  140
+	
  141
+	BOOL hasPrefix = [prefix length] > 0;
  142
+	
  143
+	const xmlChar *xmlName      = [name xmlChar];
  144
+	const xmlChar *xmlLocalName = [localName xmlChar];
  145
+	const xmlChar *xmlUri       = [uri xmlChar];
  146
+	
  147
+	xmlNodePtr child = node->children;
  148
+	while (child)
  149
+	{
  150
+		if (IsXmlNodePtr(child))
  151
+		{
  152
+			BOOL match = NO;
  153
+			
  154
+			if (uri == nil)
  155
+			{
  156
+				match = xmlStrEqual(child->name, xmlName);
  157
+			}
  158
+			else
  159
+			{
  160
+				BOOL nameMatch      = xmlStrEqual(child->name, xmlName);
  161
+				BOOL localNameMatch = xmlStrEqual(child->name, xmlLocalName);
  162
+				
  163
+				BOOL uriMatch = NO;
  164
+				if (child->ns)
  165
+				{
  166
+					uriMatch = xmlStrEqual(child->ns->href, xmlUri);
  167
+				}
  168
+				
  169
+				if (hasPrefix)
  170
+					match = nameMatch || (localNameMatch && uriMatch);
  171
+				else
  172
+					match = nameMatch && uriMatch;
  173
+			}
  174
+			
  175
+			if (match)
  176
+			{
  177
+				[result addObject:[DDXMLElement nodeWithElementPrimitive:child owner:self]];
  178
+			}
  179
+		}
  180
+		
  181
+		child = child->next;
  182
+	}
  183
+	
  184
+	return result;
  185
+}
  186
+
  187
+/**
109 188
  * Returns the child element nodes (as DDXMLElement objects) of the receiver that have a specified name.
110 189
  * 
111 190
  * If name is a qualified name, then this method invokes elementsForLocalName:URI: with the URI parameter set to
@@ -114,6 +193,10 @@ - (id)initWithXMLString:(NSString *)string error:(NSError **)error
114 193
 **/
115 194
 - (NSArray *)elementsForName:(NSString *)name
116 195
 {
  196
+#if DDXML_DEBUG_MEMORY_ISSUES
  197
+	DDXMLNotZombieAssert();
  198
+#endif
  199
+	
117 200
 	if (name == nil) return [NSArray array];
118 201
 	
119 202
 	// We need to check to see if name has a prefix.
@@ -121,132 +204,116 @@ - (NSArray *)elementsForName:(NSString *)name
121 204
 	// and then search for any elements that have the same name (including prefix) OR have the same URI.
122 205
 	// Otherwise we loop through the children as usual and do a string compare on the name
123 206
 	
124  
-	NSString *prefix = [[self class] prefixForName:name];
  207
+	NSString *prefix;
  208
+	NSString *localName;
  209
+	
  210
+	[DDXMLNode getPrefix:&prefix localName:&localName forName:name];
  211
+	
125 212
 	if ([prefix length] > 0)
126 213
 	{
127 214
 		xmlNodePtr node = (xmlNodePtr)genericPtr;
  215
+		
  216
+		// Note: We use xmlSearchNs instead of resolveNamespaceForName: because
  217
+		// we want to avoid creating wrapper objects when possible.
  218
+		
128 219
 		xmlNsPtr ns = xmlSearchNs(node->doc, node, [prefix xmlChar]);
129  
-		if (ns != NULL)
  220
+		if (ns)
130 221
 		{
131 222
 			NSString *uri = [NSString stringWithUTF8String:((const char *)ns->href)];
132  
-			return [self elementsForName:name uri:uri];
  223
+			return [self _elementsForName:name localName:localName prefix:prefix uri:uri];
133 224
 		}
134  
-		
135  
-		// Note: We used xmlSearchNs instead of resolveNamespaceForName: because
136  
-		// we want to avoid creating wrapper objects when possible.
137 225
 	}
138 226
 	
139  
-	return [self elementsForName:name uri:nil];
  227
+	return [self _elementsForName:name localName:localName prefix:prefix uri:nil];
140 228
 }
141 229
 
142  
-- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI
  230
+- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)uri
143 231
 {
  232
+#if DDXML_DEBUG_MEMORY_ISSUES
  233
+	DDXMLNotZombieAssert();
  234
+#endif
  235
+	
144 236
 	if (localName == nil) return [NSArray array];
145 237
 	
146 238
 	// We need to figure out what the prefix is for this URI.
147 239
 	// Then we search for elements that are named prefix:localName OR (named localName AND have the given URI).
148 240
 	
149  
-	NSString *prefix = [self resolvePrefixForNamespaceURI:URI];
150  
-	if (prefix != nil)
  241
+	NSString *prefix = [self _recursiveResolvePrefixForURI:uri atNode:(xmlNodePtr)genericPtr];
  242
+	if (prefix)
151 243
 	{
152 244
 		NSString *name = [NSString stringWithFormat:@"%@:%@", prefix, localName];
153 245
 		
154  
-		return [self elementsForName:name uri:URI];
  246
+		return [self _elementsForName:name localName:localName prefix:prefix uri:uri];
155 247
 	}
156 248
 	else
157 249
 	{
158  
-		return [self elementsForName:localName uri:URI];
  250
+		NSString *prefix;
  251
+		NSString *realLocalName;
  252
+		
  253
+		[DDXMLNode getPrefix:&prefix localName:&realLocalName forName:localName];
  254
+		
  255
+		return [self _elementsForName:localName localName:realLocalName prefix:prefix uri:uri];
159 256
 	}
160 257
 }
161 258
 
162  
-/**
163  
- * Helper method elementsForName and elementsForLocalName:URI: so work isn't duplicated.
164  
- * The name parameter is required, URI is optional.
165  
-**/
166  
-- (NSArray *)elementsForName:(NSString *)name uri:(NSString *)uri
  259
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  260
+#pragma mark Attributes
  261
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  262
+
  263
+- (BOOL)_hasAttributeWithName:(NSString *)name
167 264
 {
168  
-	// Supplied: name, !uri  : match: name
169  
-	// Supplied: p:name, uri : match: p:name || (name && uri)
170  
-	// Supplied: name, uri   : match: name && uri
171  
-	
172  
-	NSMutableArray *result = [NSMutableArray array];
173  
-	
174  
-	xmlNodePtr node = (xmlNodePtr)genericPtr;
  265
+	// This is a private/internal method
175 266
 	
176  
-	BOOL hasPrefix = [[[self class] prefixForName:name] length] > 0;
177  
-	NSString *localName = [[self class] localNameForName:name];
178  
-	
179  
-	xmlNodePtr child = node->children;
180  
-	while (child != NULL)
  267
+	xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
  268
+	if (attr)
181 269
 	{
182  
-		if (child->type == XML_ELEMENT_NODE)
  270
+		const xmlChar *xmlName = [name xmlChar];
  271
+		do
183 272
 		{
184  
-			BOOL match = NO;
185  
-			if (uri == nil)
186  
-			{
187  
-				match = xmlStrEqual(child->name, [name xmlChar]);
188  
-			}
189  
-			else
  273
+			if (xmlStrEqual(attr->name, xmlName))
190 274
 			{
191  
-				BOOL nameMatch = xmlStrEqual(child->name, [name xmlChar]);
192  
-				BOOL localNameMatch = xmlStrEqual(child->name, [localName xmlChar]);
193  
-				
194  
-				BOOL uriMatch = NO;
195  
-				if (child->ns != NULL)
196  
-				{
197  
-					uriMatch = xmlStrEqual(child->ns->href, [uri xmlChar]);
198  
-				}
199  
-				
200  
-				if (hasPrefix)
201  
-					match = nameMatch || (localNameMatch && uriMatch);
202  
-				else
203  
-					match = nameMatch && uriMatch;
  275
+				return YES;
204 276
 			}
  277
+			attr = attr->next;
205 278
 			
206  
-			if (match)
207  
-			{
208  
-				[result addObject:[DDXMLElement nodeWithElementPrimitive:child freeOnDealloc:NO]];
209  
-			}
210  
-		}
211  
-		
212  
-		child = child->next;
  279
+		} while (attr);
213 280
 	}
214 281
 	
215  
-	return result;
  282
+	return NO;
216 283
 }
217 284
 
218  
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
219  
-#pragma mark Attributes
220  
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
221  
-
222  
-- (BOOL)hasAttributeWithName:(NSString *)name
  285
+- (void)_removeAttributeForName:(NSString *)name
223 286
 {
  287
+	// This is a private/internal method
  288
+	
224 289
 	xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
225  
-	if (attr != NULL)
  290
+	if (attr)
226 291
 	{
227 292
 		const xmlChar *xmlName = [name xmlChar];
228  
-		
229 293
 		do
230 294
 		{
231 295
 			if (xmlStrEqual(attr->name, xmlName))
232 296
 			{
233  
-				return YES;
  297
+				[DDXMLNode removeAttribute:attr];
  298
+				return;
234 299
 			}
235 300
 			attr = attr->next;
236 301
 			
237  
-		} while (attr != NULL);
  302
+		} while(attr);
238 303
 	}
239  
-	
240  
-	return NO;
241 304
 }
242 305
 
243 306
 - (void)addAttribute:(DDXMLNode *)attribute
244 307
 {
  308
+#if DDXML_DEBUG_MEMORY_ISSUES
  309
+	DDXMLNotZombieAssert();
  310
+#endif
  311
+	
245 312
 	// NSXML version uses this same assertion
246  
-	DDXMLAssert([attribute hasParent] == NO, @"Cannot add an attribute with a parent; detach or copy first");
  313
+	DDXMLAssert([attribute _hasParent] == NO, @"Cannot add an attribute with a parent; detach or copy first");
247 314
 	DDXMLAssert(IsXmlAttrPtr(attribute->genericPtr), @"Not an attribute");
248 315
 	
249  
-	[self removeAttributeForName:[attribute name]];
  316
+	[self _removeAttributeForName:[attribute name]];
250 317
 	
251 318
 	// xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr cur)
252 319
 	// Add a new node to @parent, at the end of the child (or property) list merging
@@ -256,47 +323,30 @@ - (void)addAttribute:(DDXMLNode *)attribute
256 323
 	xmlAddChild((xmlNodePtr)genericPtr, (xmlNodePtr)attribute->genericPtr);
257 324
 	
258 325
 	// The attribute is now part of the xml tree heirarchy
259  
-	attribute->freeOnDealloc = NO;
260  
-}
261  
-
262  
-- (void)removeAttribute:(xmlAttrPtr)attr
263  
-{
264  
-	[[self class] removeAttribute:attr fromNode:(xmlNodePtr)genericPtr];
265  
-}
266  
-
267  
-- (void)removeAllAttributes
268  
-{
269  
-	[[self class] removeAllAttributesFromNode:(xmlNodePtr)genericPtr];
  326
+	attribute->owner = self;
270 327
 }
271 328
 
272 329
 - (void)removeAttributeForName:(NSString *)name
273 330
 {
274  
-	xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
275  
-	if (attr != NULL)
276  
-	{
277  
-		const xmlChar *xmlName = [name xmlChar];
278  
-		
279  
-		do
280  
-		{
281  
-			if (xmlStrEqual(attr->name, xmlName))
282  
-			{
283  
-				[self removeAttribute:attr];
284  
-				return;
285  
-			}
286  
-			attr = attr->next;
287  
-			
288  
-		} while(attr != NULL);
289  
-	}
  331
+#if DDXML_DEBUG_MEMORY_ISSUES
  332
+	DDXMLNotZombieAssert();
  333
+#endif
  334
+	
  335
+	[self _removeAttributeForName:name];
290 336
 }
291 337
 
292 338
 - (NSArray *)attributes
293 339
 {
  340
+#if DDXML_DEBUG_MEMORY_ISSUES
  341
+	DDXMLNotZombieAssert();
  342
+#endif
  343
+	
294 344
 	NSMutableArray *result = [NSMutableArray array];
295 345
 	
296 346
 	xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
297 347
 	while (attr != NULL)
298 348
 	{
299  
-		[result addObject:[DDXMLAttributeNode nodeWithAttrPrimitive:attr freeOnDealloc:NO]];
  349
+		[result addObject:[DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self]];
300 350
 		
301 351
 		attr = attr->next;
302 352
 	}
@@ -306,33 +356,40 @@ - (NSArray *)attributes
306 356
 
307 357
 - (DDXMLNode *)attributeForName:(NSString *)name
308 358
 {
309  
-	const xmlChar *attrName = [name xmlChar];
  359
+#if DDXML_DEBUG_MEMORY_ISSUES
  360
+	DDXMLNotZombieAssert();
  361
+#endif
310 362
 	
311 363
 	xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
312  
-	while (attr != NULL)
  364
+	if (attr)
313 365
 	{
314  
-		if (attr->ns && attr->ns->prefix)
  366
+		const xmlChar *xmlName = [name xmlChar];
  367
+		do
315 368
 		{
316  
-			// If the attribute name was originally something like "xml:quack",
317  
-			// then attr->name is "quack" and attr->ns->prefix is "xml".
318  
-			// 
319  
-			// So if the user is searching for "xml:quack" we need to take the prefix into account.
320  
-			// Note that "xml:quack" is what would be printed if we output the attribute.
321  
-			
322  
-			if (xmlStrQEqual(attr->ns->prefix, attr->name, attrName))
  369
+			if (attr->ns && attr->ns->prefix)
323 370
 			{
324  
-				return [DDXMLAttributeNode nodeWithAttrPrimitive:attr freeOnDealloc:NO];
  371
+				// If the attribute name was originally something like "xml:quack",
  372
+				// then attr->name is "quack" and attr->ns->prefix is "xml".
  373
+				// 
  374
+				// So if the user is searching for "xml:quack" we need to take the prefix into account.
  375
+				// Note that "xml:quack" is what would be printed if we output the attribute.
  376
+				
  377
+				if (xmlStrQEqual(attr->ns->prefix, attr->name, xmlName))
  378
+				{
  379
+					return [DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self];
  380
+				}
325 381
 			}
326  
-		}
327  
-		else
328  
-		{
329  
-			if (xmlStrEqual(attr->name, attrName))
  382
+			else
330 383
 			{
331  
-				return [DDXMLAttributeNode nodeWithAttrPrimitive:attr freeOnDealloc:NO];
  384
+				if (xmlStrEqual(attr->name, xmlName))
  385
+				{
  386
+					return [DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self];
  387
+				}
332 388
 			}
333  
-		}
334  
-		
335  
-		attr = attr->next;
  389
+			
  390
+			attr = attr->next;