2016-02-24 16:56:39 +01:00

230 lines
9.0 KiB
Objective-C

#import "DDXML.h"
// We can't rely solely on NSAssert, because many developers disable them for release builds.
// Our API contract requires us to keep these assertions intact.
#define DDXMLAssert(condition, desc, ...) \
do{ \
if(!(condition)) { \
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
object:self \
file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ \
description:(desc), ##__VA_ARGS__]; \
} \
}while(NO)
// Create assertion to ensure xml node is not a zombie.
#if DDXML_DEBUG_MEMORY_ISSUES
#define DDXMLNotZombieAssert() \
do{ \
if(DDXMLIsZombie(genericPtr, self)) { \
NSString *desc = @"XML node is a zombie - It's parent structure has been freed!"; \
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
object:self \
file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ \
description:desc]; \
} \
}while(NO)
#endif
#define DDLastErrorKey @"DDXML:LastError"
/**
* DDXMLNode can represent several underlying types, such as xmlNodePtr, xmlDocPtr, xmlAttrPtr, xmlNsPtr, etc.
* All of these are pointers to structures, and all of those structures start with a pointer, and a type.
* The xmlKind struct is used as a generic structure, and a stepping stone.
* We use it to check the type of a structure, and then perform the appropriate cast.
*
* For example:
* if(genericPtr->type == XML_ATTRIBUTE_NODE)
* {
* xmlAttrPtr attr = (xmlAttrPtr)genericPtr;
* // Do something with attr
* }
**/
struct _xmlKind {
void * ignore;
xmlElementType type;
};
typedef struct _xmlKind *xmlKindPtr;
/**
* Most xml types all start with this standard structure. In fact, all do except the xmlNsPtr.
* We will occasionally take advantage of this to simplify code when the code wouldn't vary from type to type.
* Obviously, you cannnot cast a xmlNsPtr to a xmlStdPtr.
**/
struct _xmlStd {
void * _private;
xmlElementType type;
const xmlChar *name;
struct _xmlNode *children;
struct _xmlNode *last;
struct _xmlNode *parent;
struct _xmlStd *next;
struct _xmlStd *prev;
struct _xmlDoc *doc;
};
typedef struct _xmlStd *xmlStdPtr;
NS_INLINE BOOL IsXmlAttrPtr(void *kindPtr)
{
return ((xmlKindPtr)kindPtr)->type == XML_ATTRIBUTE_NODE;
}
NS_INLINE BOOL IsXmlNodePtr(void *kindPtr)
{
switch (((xmlKindPtr)kindPtr)->type)
{
case XML_ELEMENT_NODE :
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE : return YES;
default : return NO;
}
}
NS_INLINE BOOL IsXmlDocPtr(void *kindPtr)
{
return ((xmlKindPtr)kindPtr)->type == XML_DOCUMENT_NODE;
}
NS_INLINE BOOL IsXmlDtdPtr(void *kindPtr)
{
return ((xmlKindPtr)kindPtr)->type == XML_DTD_NODE;
}
NS_INLINE BOOL IsXmlNsPtr(void *kindPtr)
{
return ((xmlKindPtr)kindPtr)->type == XML_NAMESPACE_DECL;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface DDXMLNamespaceNode : DDXMLNode
{
// The xmlNsPtr type doesn't store a reference to it's parent.
// This is here to fix the problem, and make this class more compatible with the NSXML classes.
xmlNodePtr nsParentPtr;
}
+ (id)nodeWithNsPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent owner:(DDXMLNode *)owner;
- (id)initWithNsPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent owner:(DDXMLNode *)owner;
- (xmlNodePtr)_nsParentPtr;
- (void)_setNsParentPtr:(xmlNodePtr)parentPtr;
// Overrides several methods in DDXMLNode
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface DDXMLAttributeNode : DDXMLNode
{
// The xmlAttrPtr type doesn't allow for ownership of a namespace.
//
// In other types, such as xmlNodePtr:
// - nsDef stores namespaces that are owned by the node (have been alloced by the node).
// - ns is simply a pointer to the default namespace of the node, which may or may not reside in its own nsDef list.
//
// The xmlAttrPtr only has a ns, it doesn't have a nsDef list.
// Which completely makes sense really, since namespaces have to be defined elsewhere.
//
// This is here to maintain compatibility with the NSXML classes,
// where one can assign a namespace to an attribute independently.
xmlNsPtr attrNsPtr;
}
+ (id)nodeWithAttrPrimitive:(xmlAttrPtr)attr owner:(DDXMLNode *)owner;
- (id)initWithAttrPrimitive:(xmlAttrPtr)attr owner:(DDXMLNode *)owner;
// Overrides several methods in DDXMLNode
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface DDXMLInvalidNode : DDXMLNode
{
}
// Overrides several methods in DDXMLNode
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface DDXMLNode (PrivateAPI)
+ (id)nodeWithUnknownPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner;
+ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner;
- (id)initWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner;
- (BOOL)_hasParent;
+ (void)getHasPrefix:(BOOL *)hasPrefixPtr localName:(NSString **)localNamePtr forName:(NSString *)name;
+ (void)getPrefix:(NSString **)prefixPtr localName:(NSString **)localNamePtr forName:(NSString *)name;
+ (void)recursiveStripDocPointersFromNode:(xmlNodePtr)node;
+ (void)detachNamespace:(xmlNsPtr)ns fromNode:(xmlNodePtr)node;
+ (void)removeNamespace:(xmlNsPtr)ns fromNode:(xmlNodePtr)node;
+ (void)removeAllNamespacesFromNode:(xmlNodePtr)node;
+ (void)detachAttribute:(xmlAttrPtr)attr andClean:(BOOL)clean;
+ (void)detachAttribute:(xmlAttrPtr)attr;
+ (void)removeAttribute:(xmlAttrPtr)attr;
+ (void)removeAllAttributesFromNode:(xmlNodePtr)node;
+ (void)detachChild:(xmlNodePtr)child andClean:(BOOL)clean andFixNamespaces:(BOOL)fixNamespaces;
+ (void)detachChild:(xmlNodePtr)child;
+ (void)removeChild:(xmlNodePtr)child;
+ (void)removeAllChildrenFromNode:(xmlNodePtr)node;
BOOL DDXMLIsZombie(void *xmlPtr, DDXMLNode *wrapper);
+ (NSError *)lastError;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface DDXMLElement (PrivateAPI)
+ (id)nodeWithElementPrimitive:(xmlNodePtr)node owner:(DDXMLNode *)owner;
- (id)initWithElementPrimitive:(xmlNodePtr)node owner:(DDXMLNode *)owner;
- (DDXMLNode *)_recursiveResolveNamespaceForPrefix:(NSString *)prefix atNode:(xmlNodePtr)nodePtr;
- (NSString *)_recursiveResolvePrefixForURI:(NSString *)uri atNode:(xmlNodePtr)nodePtr;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface DDXMLDocument (PrivateAPI)
+ (id)nodeWithDocPrimitive:(xmlDocPtr)doc owner:(DDXMLNode *)owner;
- (id)initWithDocPrimitive:(xmlDocPtr)doc owner:(DDXMLNode *)owner;
@end