mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +00:00
Fix and simplify memory management, init methods, other fixes.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/branches/nsxml_using_libxml2@34670 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
4a7581308d
commit
f754ea74cb
5 changed files with 265 additions and 88 deletions
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
|||
2012-01-05 22:20-EST Doug Simons <doug.simons@testplant.com>
|
||||
|
||||
* Source/NSXMLPrivate.h
|
||||
* Source/NSXMLDocument.m
|
||||
* Source/NSXMLElement.m
|
||||
* Source/NSXMLNode.m: Simplify the memory management housekeeping by
|
||||
just calling a new _updateExternalRetains method after any operations
|
||||
that might have changed the retains. This still needs some cleaning up,
|
||||
but is working much better now.
|
||||
Clean up and simplify some of the init methods.
|
||||
Fix a few other things.
|
||||
|
||||
2012-01-29 12:28-EST Gregory John Casamento <greg.casamento@gmail.com>
|
||||
|
||||
* Source/NSXMLNode.m: Correct infinite loop in releaseExtraRetains.
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
#import "GSInternal.h"
|
||||
GS_PRIVATE_INTERNAL(NSXMLDocument)
|
||||
|
||||
#import <Foundation/NSXMLParser.h>
|
||||
//#import <Foundation/NSXMLParser.h>
|
||||
#import <Foundation/NSError.h>
|
||||
|
||||
extern void clearPrivatePointers(xmlNodePtr aNode);
|
||||
|
||||
|
@ -116,15 +117,14 @@ extern void clearPrivatePointers(xmlNodePtr aNode);
|
|||
{
|
||||
if (NSXMLDocumentKind == kind)
|
||||
{
|
||||
/* Create holder for internal instance variables so that we'll have
|
||||
* all our ivars available rather than just those of the superclass.
|
||||
*/
|
||||
xmlChar *version = (xmlChar *)"1.0";
|
||||
GS_CREATE_INTERNAL(NSXMLDocument);
|
||||
internal->node = xmlNewDoc(version);
|
||||
MY_DOC->_private = (void *)self;
|
||||
return [super initWithKind: kind options: theOptions];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self release];
|
||||
return [[NSXMLNode alloc] initWithKind: kind
|
||||
options: theOptions];
|
||||
}
|
||||
return [super initWithKind: kind options: theOptions];
|
||||
}
|
||||
|
||||
- (id) initWithRootElement: (NSXMLElement*)element
|
||||
|
@ -161,26 +161,27 @@ extern void clearPrivatePointers(xmlNodePtr aNode);
|
|||
format: @"[NSXMLDocument-%@] invalid argument",
|
||||
NSStringFromSelector(_cmd)];
|
||||
}
|
||||
GS_CREATE_INTERNAL(NSXMLDocument)
|
||||
if ((self = [super initWithKind: NSXMLDocumentKind options: 0]) != nil)
|
||||
if ((self = [self initWithKind: NSXMLDocumentKind options: 0]) != nil)
|
||||
{
|
||||
const char *str = [string UTF8String];
|
||||
char *url = NULL;
|
||||
char *encoding = NULL; // "UTF8";
|
||||
int options = XML_PARSE_NOERROR;
|
||||
xmlDocPtr doc = NULL;
|
||||
if (!(mask & NSXMLNodePreserveWhitespace))
|
||||
options |= XML_PARSE_NOBLANKS;
|
||||
//xmlKeepBlanksDefault(0);
|
||||
GS_CREATE_INTERNAL(NSXMLDocument); // create internal ivars...
|
||||
internal->node = xmlReadDoc((xmlChar *)str, url, encoding, options);
|
||||
if(internal->node == NULL)
|
||||
doc = xmlReadDoc((xmlChar *)str, url, encoding, options);
|
||||
if(doc == NULL)
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
[NSException raise:NSInvalidArgumentException
|
||||
format:@"Cannot instantiate NSXMLDocument with invalid data"];
|
||||
if (error != NULL)
|
||||
*error = [NSError errorWithDomain:@"NSXMLErrorDomain" code:0 userInfo:nil];
|
||||
//[NSException raise:NSInvalidArgumentException
|
||||
// format:@"Cannot instantiate NSXMLDocument with invalid data"];
|
||||
}
|
||||
MY_DOC->_private = (void *)self;
|
||||
[self _setNode:doc];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
|
@ -67,38 +67,34 @@ extern void clearPrivatePointers(xmlNodePtr aNode);
|
|||
return [self initWithKind: NSXMLElementKind options: 0];
|
||||
}
|
||||
|
||||
- (id) initWithKind: (NSXMLNodeKind)kind options: (NSUInteger)theOptions
|
||||
{
|
||||
if (NSXMLElementKind == kind)
|
||||
{
|
||||
if ((self = [super initWithKind:kind options:theOptions]))
|
||||
{
|
||||
internal->objectValue = @"";
|
||||
}
|
||||
return self;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self release];
|
||||
return [[NSXMLNode alloc] initWithKind: kind
|
||||
options: theOptions];
|
||||
}
|
||||
}
|
||||
|
||||
- (id) initWithName: (NSString*)name
|
||||
{
|
||||
return [self initWithName: name URI: nil];
|
||||
}
|
||||
|
||||
- (id) initWithKind: (NSXMLNodeKind)kind options: (NSUInteger)theOptions
|
||||
{
|
||||
if (NSXMLElementKind == kind)
|
||||
{
|
||||
/* Create holder for internal instance variables so that we'll have
|
||||
* all our ivars available rather than just those of the superclass.
|
||||
*/
|
||||
NSString *name = @"";
|
||||
GS_CREATE_INTERNAL(NSXMLElement)
|
||||
internal->node = (void *)xmlNewNode(NULL,(xmlChar *)[name UTF8String]);
|
||||
((xmlNodePtr)internal->node)->_private = self;
|
||||
internal->objectValue = @"";
|
||||
// return self;
|
||||
}
|
||||
return [super initWithKind: kind options: theOptions];
|
||||
}
|
||||
|
||||
- (id) initWithName: (NSString*)name URI: (NSString*)URI
|
||||
{
|
||||
/* Create holder for internal instance variables so that we'll have
|
||||
* all our ivars available rather than just those of the superclass.
|
||||
*/
|
||||
GS_CREATE_INTERNAL(NSXMLElement)
|
||||
if ((self = [super initWithKind: NSXMLElementKind]) != nil)
|
||||
{
|
||||
internal->node = (void *)xmlNewNode(NULL,(xmlChar *)[name UTF8String]);
|
||||
((xmlNodePtr)internal->node)->_private = self;
|
||||
[self setName:name];
|
||||
ASSIGNCOPY(internal->URI, URI);
|
||||
internal->objectValue = @"";
|
||||
}
|
||||
|
@ -367,7 +363,7 @@ extern void clearPrivatePointers(xmlNodePtr aNode);
|
|||
}
|
||||
else if(index < childCount)
|
||||
{
|
||||
xmlAddNextSibling(curNode, childNode);
|
||||
xmlAddPrevSibling(curNode, childNode);
|
||||
}
|
||||
|
||||
[self _addSubNode:child];
|
||||
|
@ -398,6 +394,7 @@ extern void clearPrivatePointers(xmlNodePtr aNode);
|
|||
child = [[self children] objectAtIndex: index];
|
||||
n = [child _node];
|
||||
xmlUnlinkNode(n);
|
||||
[self _removeSubNode:child];
|
||||
}
|
||||
|
||||
- (void) setChildren: (NSArray*)children
|
||||
|
|
|
@ -101,16 +101,111 @@ GS_PRIVATE_INTERNAL(NSXMLNode)
|
|||
return result;
|
||||
}
|
||||
|
||||
- (int) _externalRetains
|
||||
{
|
||||
return internal->externalRetains;
|
||||
}
|
||||
|
||||
- (int) verifyExternalRetains
|
||||
{
|
||||
int extraRetains = ([self retainCount] > 1 ? 1 : 0); // start with 1 or 0 for ourself
|
||||
int index;
|
||||
for (index = 0; index < [internal->subNodes count]; index++)
|
||||
extraRetains += [[internal->subNodes objectAtIndex:index] _externalRetains];
|
||||
return extraRetains;
|
||||
}
|
||||
|
||||
- (void) _updateExternalRetains
|
||||
{
|
||||
xmlNodePtr pnode = MY_NODE->parent;
|
||||
NSXMLNode *parent = (NSXMLNode *)(pnode ? pnode->_private : nil);
|
||||
int oldCount = internal->externalRetains;
|
||||
int extraRetains = ([self retainCount] > 1 ? 1 : 0); // start with 1 or 0 for ourself
|
||||
int index;
|
||||
for (index = 0; index < [internal->subNodes count]; index++)
|
||||
extraRetains += [[internal->subNodes objectAtIndex:index] _externalRetains];
|
||||
internal->externalRetains = extraRetains;
|
||||
if (extraRetains != oldCount)
|
||||
{
|
||||
if (parent)
|
||||
[parent _updateExternalRetains]; // tell our parent (if any) since our count has changed
|
||||
else
|
||||
{ // we're the root node of this tree, so retain or release ourself as needed
|
||||
if (oldCount == 0 && extraRetains > 0)
|
||||
{
|
||||
[super retain];
|
||||
internal->retainedSelf++;
|
||||
//NSLog(@"RETAINED SELF %@ (%d)", self, internal->retainedSelf);
|
||||
}
|
||||
else if (oldCount > 0 && extraRetains == 0 && internal->retainedSelf)
|
||||
{
|
||||
internal->retainedSelf--;
|
||||
//NSLog(@"RELEASED SELF %@ (%d)", self, internal->retainedSelf);
|
||||
[super release];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!parent)
|
||||
{
|
||||
if (extraRetains > 0 && internal->retainedSelf == 0)
|
||||
{
|
||||
[super retain];
|
||||
internal->retainedSelf++;
|
||||
//NSLog(@"RETAINED SELF AFTER STATUS CHANGED %@ (%d)", self, internal->retainedSelf);
|
||||
}
|
||||
else if (extraRetains == 0 && internal->retainedSelf > 0)
|
||||
{
|
||||
internal->retainedSelf--;
|
||||
//NSLog(@"RELEASED SELF AFTER STATUS CHANGED %@ (%d)", self, internal->retainedSelf);
|
||||
[super release];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) _passExternalRetainsTo:(NSXMLNode *)parent
|
||||
{
|
||||
// this object just became a subNode, so pass responsibility for external retains up the line
|
||||
BOOL releaseSelf = (internal->externalRetains > 0); // if we've retained ourself
|
||||
while (internal->externalRetains-- > 0)
|
||||
// this object just became a subNode, so pass knowledge of external retains up the line
|
||||
if (internal->externalRetains > 0)
|
||||
{
|
||||
[parent recordExternalRetain];
|
||||
//NSLog(@"_passExternalRetainsTo:%@ (%d,%d) from %@ Start:(%d,%d)", parent, [parent _externalRetains], [parent verifyExternalRetains], self, internal->externalRetains, [self verifyExternalRetains]);
|
||||
// if ([self retainCount] == 2)
|
||||
// {
|
||||
// internal->externalRetains--;
|
||||
//NSLog(@"RELEASING TRICKY EXTRA RETAIN WHILE ADDING TO PARENT in %@ now: %d", self, internal->externalRetains);
|
||||
// }
|
||||
//[self _updateExternalRetains];
|
||||
if (internal->retainedSelf)
|
||||
{
|
||||
[super release]; // we're no longer the root of our branch, so stop retaining ourself
|
||||
internal->retainedSelf--;
|
||||
//NSLog(@"RELEASED SELF %@ (%d) in _passExternal...", self, internal->retainedSelf);
|
||||
}
|
||||
[parent _updateExternalRetains];
|
||||
//NSLog(@"DID _passExternalRetainsTo:%@ (%d,%d) from %@ End:(%d,%d)", parent, [parent _externalRetains], [parent verifyExternalRetains], self, internal->externalRetains, [self verifyExternalRetains]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) _removeExternalRetainsFrom:(NSXMLNode *)parent
|
||||
{
|
||||
// this object is no longer a subNode, so pass removal of external retains up the line
|
||||
if (internal->externalRetains > 0)
|
||||
{
|
||||
//NSLog(@"_removeExternalRetainsTo:%@ from %@ Start: %d", parent, self, internal->externalRetains);
|
||||
/// [parent releaseExternalRetain:internal->externalRetains];
|
||||
if ([self retainCount] == 1)
|
||||
{
|
||||
internal->externalRetains++;
|
||||
//NSLog(@"ADDED TRICKY EXTRA COUNT WHILE REMOVING FROM PARENT in %@ now: %d subNodes(low):%d", self, internal->externalRetains, [self verifyExternalRetains]);
|
||||
}
|
||||
|
||||
[super retain]; // becoming detached, so retain ourself as the new root of our branch
|
||||
internal->retainedSelf++;
|
||||
//NSLog(@"RETAINED SELF %@ (%d) in _removeExternal...", self, internal->retainedSelf);
|
||||
[parent _updateExternalRetains];
|
||||
}
|
||||
if (releaseSelf)
|
||||
[self release];
|
||||
}
|
||||
|
||||
- (void) _addSubNode:(NSXMLNode *)subNode
|
||||
|
@ -126,7 +221,10 @@ GS_PRIVATE_INTERNAL(NSXMLNode)
|
|||
|
||||
- (void) _removeSubNode:(NSXMLNode *)subNode
|
||||
{
|
||||
[subNode retain]; // retain temporarily so we can safely remove from our subNodes list first
|
||||
[internal->subNodes removeObjectIdenticalTo:subNode];
|
||||
[subNode _removeExternalRetainsFrom:self];
|
||||
[subNode release]; // release temporary hold
|
||||
}
|
||||
|
||||
- (void) _createInternal
|
||||
|
@ -537,53 +635,71 @@ NSArray *execute_xpath(NSXMLNode *node,
|
|||
return c;
|
||||
}
|
||||
|
||||
- (void) recordExternalRetain
|
||||
/** these methods should go away now
|
||||
- (void) recordExternalRetain:(int)count
|
||||
{
|
||||
id parent = [self parent];
|
||||
if (parent)
|
||||
[parent recordExternalRetain];
|
||||
[parent recordExternalRetain:count];
|
||||
else
|
||||
{
|
||||
if (internal->externalRetains == 0)
|
||||
[super retain]; // the top of the tree retains itself whenever there are external retains anywhere
|
||||
internal->externalRetains++;
|
||||
if (count > 0 && internal->externalRetains == 0)
|
||||
{
|
||||
[super retain]; // the top of the tree retains itself whenever there are external retains anywhere
|
||||
if ([self retainCount] == 2)
|
||||
{
|
||||
internal->externalRetains++;
|
||||
NSLog(@"ADDED TRICKY EXTRA COUNT in %@ now: %d subNodes(OFF):%d", self, internal->externalRetains, [self verifyExternalRetains]);
|
||||
}
|
||||
}
|
||||
}
|
||||
internal->externalRetains += count;
|
||||
NSLog(@"recordExternalRetain in %@ now: %d subNodes:%d", self, internal->externalRetains, [self verifyExternalRetains]);
|
||||
}
|
||||
|
||||
- (void) releaseExternalRetain
|
||||
- (void) releaseExternalRetain:(int)count
|
||||
{
|
||||
id parent = [self parent];
|
||||
internal->externalRetains -= count;
|
||||
if (internal->externalRetains <0)
|
||||
NSLog(@"ExternalRetains going NEGATIVE: %d in %@", internal->externalRetains - count, self);
|
||||
|
||||
NSLog(@"releaseExternalRetain in %@ now: %d", self, internal->externalRetains);
|
||||
if (parent)
|
||||
[parent releaseExternalRetain];
|
||||
[parent releaseExternalRetain:count];
|
||||
else
|
||||
{
|
||||
if (internal->externalRetains <=0)
|
||||
NSLog(@"ExternalRetains going NEGATIVE: %d in %@", internal->externalRetains - 1, self);
|
||||
internal->externalRetains--;
|
||||
if (internal->externalRetains == 0)
|
||||
// check for tricky condition where our only "external" retain is from ourself and is about to go away
|
||||
if (count > 0 && internal->externalRetains == 1 && [self retainCount] == 2)
|
||||
{
|
||||
internal->externalRetains--;
|
||||
NSLog(@"RELEASING TRICKY EXTRA RETAIN in %@ now: %d", self, internal->externalRetains);
|
||||
}
|
||||
if (count > 0 && internal->externalRetains == 0)
|
||||
[super release]; // the top of the tree retains itself whenever there are external retains anywhere
|
||||
}
|
||||
}
|
||||
**/
|
||||
|
||||
- (id) retain
|
||||
{
|
||||
if ([self retainCount] == 1)
|
||||
[super retain]; // do this first
|
||||
if ([self retainCount] == 2)
|
||||
{
|
||||
[self recordExternalRetain];
|
||||
[self _updateExternalRetains]; //[self recordExternalRetain:1];
|
||||
}
|
||||
return [super retain];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) release
|
||||
{
|
||||
if(GS_EXISTS_INTERNAL)
|
||||
if ([self retainCount] == 2)
|
||||
{
|
||||
if ([self retainCount] == [internal->subNodes count]) // 2)
|
||||
{
|
||||
[self releaseExternalRetain];
|
||||
}
|
||||
[super release];
|
||||
[self _updateExternalRetains]; //[self releaseExternalRetain:1];
|
||||
}
|
||||
[super release];
|
||||
else
|
||||
[super release];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
|
@ -594,6 +710,8 @@ if (internal->externalRetains <=0)
|
|||
[internal->URI release];
|
||||
[internal->objectValue release];
|
||||
[internal->subNodes release];
|
||||
if (node)
|
||||
node->_private = NULL;
|
||||
if (node && node->parent == NULL)
|
||||
{
|
||||
xmlFree(node); // the top level node frees the entire tree
|
||||
|
@ -608,10 +726,29 @@ if (internal->externalRetains <=0)
|
|||
xmlNodePtr node = (xmlNodePtr)(internal->node);
|
||||
if(node)
|
||||
{
|
||||
int extraRetains = 0;
|
||||
xmlNodePtr parentNode = node->parent;
|
||||
NSXMLNode *parent = (parentNode ? parentNode->_private : nil); // get our parent object if it exists
|
||||
[parent _removeSubNode:self];
|
||||
xmlUnlinkNode(node);
|
||||
xmlUnlinkNode(node); // separate our node from its parent and siblings
|
||||
if (parent)
|
||||
{
|
||||
// transfer extra retains of this branch from our parent to ourself
|
||||
extraRetains = internal->externalRetains; //[self verifyExternalRetains];
|
||||
if (extraRetains)
|
||||
{
|
||||
/// [parent releaseExternalRetain:extraRetains];
|
||||
if ([self retainCount] == 1)
|
||||
{
|
||||
internal->externalRetains++;
|
||||
//NSLog(@"ADDED TRICKY EXTRA COUNT WHILE DETACHING in %@ now: %d subNodes(low):%d", self, internal->externalRetains, [self verifyExternalRetains]);
|
||||
}
|
||||
[super retain]; //[self recordExternalRetain:extraRetains];
|
||||
internal->retainedSelf++;
|
||||
//NSLog(@"RETAINED SELF %@ (%d) in detach", self, internal->retainedSelf);
|
||||
}
|
||||
[parent _removeSubNode:self];
|
||||
}
|
||||
//NSLog(@"DETACHED %@ from %@ and transferred extra retains: %d", self, parent, extraRetains);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -659,33 +796,75 @@ if (internal->externalRetains <=0)
|
|||
switch (kind)
|
||||
{
|
||||
case NSXMLDocumentKind:
|
||||
node = xmlNewDoc((xmlChar *)"1.0");
|
||||
theSubclass = [NSXMLDocument class];
|
||||
break;
|
||||
|
||||
case NSXMLInvalidKind:
|
||||
case NSXMLElementKind:
|
||||
node = xmlNewNode(NULL,(xmlChar *)"");
|
||||
theSubclass = [NSXMLElement class];
|
||||
break;
|
||||
|
||||
case NSXMLDTDKind:
|
||||
node = xmlNewDtd(NULL, (xmlChar *)"", (xmlChar *)"",(xmlChar *)"");
|
||||
theSubclass = [NSXMLDTD class];
|
||||
break;
|
||||
|
||||
case NSXMLEntityDeclarationKind:
|
||||
case NSXMLElementDeclarationKind:
|
||||
case NSXMLNotationDeclarationKind:
|
||||
node = xmlNewNode(NULL, (xmlChar *)"");
|
||||
// ((xmlNodePtr)node)->type = XML_ATTRIBUTE_DECL;
|
||||
theSubclass = [NSXMLDTDNode class];
|
||||
break;
|
||||
|
||||
case NSXMLAttributeDeclarationKind:
|
||||
[self release];
|
||||
return nil;
|
||||
break;
|
||||
|
||||
case NSXMLProcessingInstructionKind:
|
||||
case NSXMLCommentKind:
|
||||
case NSXMLTextKind:
|
||||
case NSXMLNamespaceKind:
|
||||
case NSXMLAttributeKind:
|
||||
break;
|
||||
|
||||
default:
|
||||
kind = NSXMLInvalidKind;
|
||||
theSubclass = [NSXMLElement class];
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether we are already initializing an instance of the given
|
||||
* subclass. If we are not, release ourselves and allocate a subclass instance
|
||||
* instead.
|
||||
*/
|
||||
if (NO == [self isKindOfClass: theSubclass])
|
||||
{
|
||||
[self release];
|
||||
return [[theSubclass alloc] initWithKind: kind
|
||||
options: theOptions];
|
||||
}
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case NSXMLDocumentKind:
|
||||
node = xmlNewDoc((xmlChar *)"1.0");
|
||||
break;
|
||||
|
||||
case NSXMLInvalidKind:
|
||||
case NSXMLElementKind:
|
||||
node = xmlNewNode(NULL,(xmlChar *)"");
|
||||
break;
|
||||
|
||||
case NSXMLDTDKind:
|
||||
node = xmlNewDtd(NULL, (xmlChar *)"", (xmlChar *)"",(xmlChar *)"");
|
||||
break;
|
||||
|
||||
case NSXMLEntityDeclarationKind:
|
||||
case NSXMLElementDeclarationKind:
|
||||
case NSXMLNotationDeclarationKind:
|
||||
node = xmlNewNode(NULL, (xmlChar *)"");
|
||||
break;
|
||||
|
||||
case NSXMLProcessingInstructionKind:
|
||||
node = xmlNewPI((xmlChar *)"", (xmlChar *)"");
|
||||
break;
|
||||
|
@ -694,7 +873,6 @@ if (internal->externalRetains <=0)
|
|||
node = xmlNewComment((xmlChar *)"");
|
||||
break;
|
||||
|
||||
|
||||
case NSXMLTextKind:
|
||||
node = xmlNewText((xmlChar *)"");
|
||||
break;
|
||||
|
@ -711,21 +889,9 @@ if (internal->externalRetains <=0)
|
|||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether we are already initializing an instance of the given
|
||||
* subclass. If we are not, release ourselves and allocate a subclass instance
|
||||
* instead.
|
||||
*/
|
||||
if (NO == [self isKindOfClass: theSubclass])
|
||||
{
|
||||
[self release];
|
||||
return [[theSubclass alloc] initWithKind: kind
|
||||
options: theOptions];
|
||||
}
|
||||
|
||||
/* Create holder for internal instance variables if needed.
|
||||
*/
|
||||
GS_CREATE_INTERNAL(NSXMLNode);
|
||||
[self _createInternal];
|
||||
|
||||
/* Create libxml object to go with it...
|
||||
*/
|
||||
|
|
|
@ -114,6 +114,7 @@ StringFromXMLString(const unsigned char *bytes, unsigned length)
|
|||
NSMutableArray *subNodes; \
|
||||
NSString *xpath; \
|
||||
int externalRetains; \
|
||||
int retainedSelf; \
|
||||
|
||||
|
||||
/* When using the non-fragile ABI, the instance variables are exposed to the
|
||||
|
|
Loading…
Reference in a new issue