Newer
Older
* tree.c : implementation of access function for an XML tree.
* References:
* XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
*
* See Copyright for the status of this software.
*
/* To avoid EBCDIC trouble when parsing on zOS */
#if defined(__MVS__)
#pragma convert("ISO8859-1")
#endif
#define IN_LIBXML
#include <string.h> /* for memset() only ! */
#include <limits.h>
#include <ctype.h>
#include <stdlib.h>
#include <zlib.h>
#endif
#include <libxml/xmlmemory.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/uri.h>
#include <libxml/entities.h>
#include <libxml/valid.h>
#include <libxml/xmlerror.h>
#include <libxml/parserInternals.h>
#include <libxml/globals.h>
#ifdef LIBXML_HTML_ENABLED
#include <libxml/HTMLtree.h>
#endif
William M. Brack
committed
#ifdef LIBXML_DEBUG_ENABLED
#include <libxml/debugXML.h>
#endif
int __xmlRegisterCallbacks = 0;
Kasimier T. Buchcik
committed
/************************************************************************
* *
* Forward declarations *
Kasimier T. Buchcik
committed
* *
************************************************************************/
xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
Kasimier T. Buchcik
committed
/************************************************************************
* *
* Tree memory error handler *
* *
************************************************************************/
/**
* xmlTreeErrMemory:
*
* Handle an out of memory condition
*/
static void
xmlTreeErrMemory(const char *extra)
{
__xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
}
/**
* xmlTreeErr:
* @code: the error number
*
* Handle an out of memory condition
*/
static void
xmlTreeErr(int code, xmlNodePtr node, const char *extra)
{
const char *msg = NULL;
switch(code) {
case XML_TREE_INVALID_HEX:
msg = "invalid hexadecimal character value\n";
break;
case XML_TREE_INVALID_DEC:
msg = "invalid decimal character value\n";
break;
case XML_TREE_UNTERMINATED_ENTITY:
msg = "unterminated entity reference %15s\n";
break;
case XML_TREE_NOT_UTF8:
msg = "string is not in UTF-8\n";
break;
default:
msg = "unexpected error number\n";
}
__xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
}
/************************************************************************
* *
* A few static variables and macros *
* *
************************************************************************/
/* #undef xmlStringText */
const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
/* #undef xmlStringTextNoenc */
const xmlChar xmlStringTextNoenc[] =
{ 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
/* #undef xmlStringComment */
const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
static int xmlCompressMode = 0;
static int xmlCheckDTD = 1;
#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
xmlNodePtr ulccur = (n)->children; \
if (ulccur == NULL) { \
(n)->last = NULL; \
} else { \
while (ulccur->next != NULL) { \
ulccur->parent = (n); \
ulccur = ulccur->next; \
} \
ulccur->parent = (n); \
(n)->last = ulccur; \
}}
Kasimier T. Buchcik
committed
#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
(str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
/* #define DEBUG_BUFFER */
/* #define DEBUG_TREE */
/************************************************************************
* *
* Functions to move to entities.c once the *
Daniel Veillard
committed
* API freeze is smoothen and they can be made public. *
* *
************************************************************************/
#include <libxml/hash.h>
#ifdef LIBXML_TREE_ENABLED
Daniel Veillard
committed
/**
* xmlGetEntityFromDtd:
* @dtd: A pointer to the DTD to search
* @name: The entity name
*
* Do an entity lookup in the DTD entity hash table and
* return the corresponding entity, if found.
*
Daniel Veillard
committed
* Returns A pointer to the entity structure or NULL if not found.
*/
static xmlEntityPtr
xmlGetEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
Daniel Veillard
committed
xmlEntitiesTablePtr table;
Daniel Veillard
committed
if((dtd != NULL) && (dtd->entities != NULL)) {
table = (xmlEntitiesTablePtr) dtd->entities;
return((xmlEntityPtr) xmlHashLookup(table, name));
/* return(xmlGetEntityFromTable(table, name)); */
Daniel Veillard
committed
}
return(NULL);
}
/**
* xmlGetParameterEntityFromDtd:
* @dtd: A pointer to the DTD to search
* @name: The entity name
*
* Do an entity lookup in the DTD parameter entity hash table and
Daniel Veillard
committed
* return the corresponding entity, if found.
*
* Returns A pointer to the entity structure or NULL if not found.
*/
static xmlEntityPtr
xmlGetParameterEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
Daniel Veillard
committed
xmlEntitiesTablePtr table;
Daniel Veillard
committed
if ((dtd != NULL) && (dtd->pentities != NULL)) {
table = (xmlEntitiesTablePtr) dtd->pentities;
return((xmlEntityPtr) xmlHashLookup(table, name));
/* return(xmlGetEntityFromTable(table, name)); */
}
return(NULL);
}
#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard
committed
/************************************************************************
* *
* QName handling helper *
* *
************************************************************************/
/**
* xmlBuildQName:
* @ncname: the Name
* @prefix: the prefix
* @memory: preallocated memory
* @len: preallocated memory length
*
* Builds the QName @prefix:@ncname in @memory if there is enough space
* and prefix is not NULL nor empty, otherwise allocate a new string.
* If prefix is NULL or empty it returns ncname.
*
* Returns the new string which must be freed by the caller if different from
* @memory and @ncname or NULL in case of error
*/
xmlChar *
xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
xmlChar *memory, int len) {
int lenn, lenp;
xmlChar *ret;
if (ncname == NULL) return(NULL);
if (prefix == NULL) return((xmlChar *) ncname);
lenn = strlen((char *) ncname);
lenp = strlen((char *) prefix);
if ((memory == NULL) || (len < lenn + lenp + 2)) {
ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
if (ret == NULL) {
xmlTreeErrMemory("building QName");
return(NULL);
}
} else {
ret = memory;
}
memcpy(&ret[0], prefix, lenp);
ret[lenp] = ':';
memcpy(&ret[lenp + 1], ncname, lenn);
ret[lenn + lenp + 1] = 0;
return(ret);
}
/**
* xmlSplitQName2:
* @name: the full QName
* @prefix: a xmlChar **
*
* parse an XML qualified name string
*
* [NS 5] QName ::= (Prefix ':')? LocalPart
*
* [NS 6] Prefix ::= NCName
*
* [NS 7] LocalPart ::= NCName
*
* Returns NULL if the name doesn't have a prefix. Otherwise, returns the
* local part, and prefix is updated to get the Prefix. Both the return value
* and the prefix must be freed by the caller.
*/
xmlChar *
xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
int len = 0;
xmlChar *ret = NULL;
if (prefix == NULL) return(NULL);
*prefix = NULL;
if (name == NULL) return(NULL);
#ifndef XML_XML_NAMESPACE
/* xml: prefix is not really a namespace */
if ((name[0] == 'x') && (name[1] == 'm') &&
(name[2] == 'l') && (name[3] == ':'))
return(NULL);
#endif
/* nasty but valid */
if (name[0] == ':')
return(NULL);
/*
* we are not trying to validate but just to cut, and yes it will
* work even if this is as set of UTF-8 encoded chars
*/
while ((name[len] != 0) && (name[len] != ':'))
len++;
if (name[len] == 0)
return(NULL);
*prefix = xmlStrndup(name, len);
if (*prefix == NULL) {
xmlTreeErrMemory("QName split");
return(NULL);
}
ret = xmlStrdup(&name[len + 1]);
if (ret == NULL) {
xmlTreeErrMemory("QName split");
if (*prefix != NULL) {
xmlFree(*prefix);
*prefix = NULL;
}
return(NULL);
}
return(ret);
}
/**
* xmlSplitQName3:
* @name: the full QName
* @len: an int *
*
* parse an XML qualified name string,i
*
* returns NULL if it is not a Qualified Name, otherwise, update len
* with the length in byte of the prefix and return a pointer
* to the start of the name without the prefix
*/
const xmlChar *
xmlSplitQName3(const xmlChar *name, int *len) {
int l = 0;
if (name == NULL) return(NULL);
if (len == NULL) return(NULL);
/* nasty but valid */
if (name[0] == ':')
return(NULL);
/*
* we are not trying to validate but just to cut, and yes it will
* work even if this is as set of UTF-8 encoded chars
*/
while ((name[l] != 0) && (name[l] != ':'))
l++;
if (name[l] == 0)
return(NULL);
*len = l;
return(&name[l+1]);
}
/************************************************************************
* *
* Check Name, NCName and QName strings *
* *
************************************************************************/
#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
/**
* xmlValidateNCName:
* @value: the value to check
* @space: allow spaces in front and end of the string
*
* Check that a value conforms to the lexical space of NCName
*
* Returns 0 if this validates, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlValidateNCName(const xmlChar *value, int space) {
const xmlChar *cur = value;
int c,l;
if (value == NULL)
return(-1);
/*
* First quick algorithm for ASCII range
*/
if (space)
while (IS_BLANK_CH(*cur)) cur++;
if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
(*cur == '_'))
cur++;
else
goto try_complex;
while (((*cur >= 'a') && (*cur <= 'z')) ||
((*cur >= 'A') && (*cur <= 'Z')) ||
((*cur >= '0') && (*cur <= '9')) ||
(*cur == '_') || (*cur == '-') || (*cur == '.'))
cur++;
if (space)
while (IS_BLANK_CH(*cur)) cur++;
if (*cur == 0)
return(0);
try_complex:
/*
* Second check for chars outside the ASCII range
*/
cur = value;
c = CUR_SCHAR(cur, l);
if (space) {
while (IS_BLANK(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
}
William M. Brack
committed
if ((!IS_LETTER(c)) && (c != '_'))
return(1);
cur += l;
c = CUR_SCHAR(cur, l);
William M. Brack
committed
while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
(c == '-') || (c == '_') || IS_COMBINING(c) ||
IS_EXTENDER(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
if (space) {
while (IS_BLANK(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
}
if (c != 0)
return(1);
return(0);
}
#endif
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
/**
* xmlValidateQName:
* @value: the value to check
* @space: allow spaces in front and end of the string
*
* Check that a value conforms to the lexical space of QName
*
* Returns 0 if this validates, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlValidateQName(const xmlChar *value, int space) {
const xmlChar *cur = value;
int c,l;
if (value == NULL)
return(-1);
/*
* First quick algorithm for ASCII range
*/
if (space)
while (IS_BLANK_CH(*cur)) cur++;
if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
(*cur == '_'))
cur++;
else
goto try_complex;
while (((*cur >= 'a') && (*cur <= 'z')) ||
((*cur >= 'A') && (*cur <= 'Z')) ||
((*cur >= '0') && (*cur <= '9')) ||
(*cur == '_') || (*cur == '-') || (*cur == '.'))
cur++;
if (*cur == ':') {
cur++;
if (((*cur >= 'a') && (*cur <= 'z')) ||
((*cur >= 'A') && (*cur <= 'Z')) ||
(*cur == '_'))
cur++;
else
goto try_complex;
while (((*cur >= 'a') && (*cur <= 'z')) ||
((*cur >= 'A') && (*cur <= 'Z')) ||
((*cur >= '0') && (*cur <= '9')) ||
(*cur == '_') || (*cur == '-') || (*cur == '.'))
cur++;
}
if (space)
while (IS_BLANK_CH(*cur)) cur++;
if (*cur == 0)
return(0);
try_complex:
/*
* Second check for chars outside the ASCII range
*/
cur = value;
c = CUR_SCHAR(cur, l);
if (space) {
while (IS_BLANK(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
}
William M. Brack
committed
if ((!IS_LETTER(c)) && (c != '_'))
return(1);
cur += l;
c = CUR_SCHAR(cur, l);
William M. Brack
committed
while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
(c == '-') || (c == '_') || IS_COMBINING(c) ||
IS_EXTENDER(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
if (c == ':') {
cur += l;
c = CUR_SCHAR(cur, l);
William M. Brack
committed
if ((!IS_LETTER(c)) && (c != '_'))
return(1);
cur += l;
c = CUR_SCHAR(cur, l);
William M. Brack
committed
while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
(c == '-') || (c == '_') || IS_COMBINING(c) ||
IS_EXTENDER(c)) {
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
cur += l;
c = CUR_SCHAR(cur, l);
}
}
if (space) {
while (IS_BLANK(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
}
if (c != 0)
return(1);
return(0);
}
/**
* xmlValidateName:
* @value: the value to check
* @space: allow spaces in front and end of the string
*
* Check that a value conforms to the lexical space of Name
*
* Returns 0 if this validates, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlValidateName(const xmlChar *value, int space) {
const xmlChar *cur = value;
int c,l;
if (value == NULL)
return(-1);
/*
* First quick algorithm for ASCII range
*/
if (space)
while (IS_BLANK_CH(*cur)) cur++;
if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
(*cur == '_') || (*cur == ':'))
cur++;
else
goto try_complex;
while (((*cur >= 'a') && (*cur <= 'z')) ||
((*cur >= 'A') && (*cur <= 'Z')) ||
((*cur >= '0') && (*cur <= '9')) ||
(*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
cur++;
if (space)
while (IS_BLANK_CH(*cur)) cur++;
if (*cur == 0)
return(0);
try_complex:
/*
* Second check for chars outside the ASCII range
*/
cur = value;
c = CUR_SCHAR(cur, l);
if (space) {
while (IS_BLANK(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
}
William M. Brack
committed
if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
return(1);
cur += l;
c = CUR_SCHAR(cur, l);
William M. Brack
committed
while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
(c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
if (space) {
while (IS_BLANK(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
}
if (c != 0)
return(1);
return(0);
}
Daniel Veillard
committed
/**
* xmlValidateNMToken:
* @value: the value to check
* @space: allow spaces in front and end of the string
*
* Check that a value conforms to the lexical space of NMToken
*
* Returns 0 if this validates, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlValidateNMToken(const xmlChar *value, int space) {
const xmlChar *cur = value;
int c,l;
if (value == NULL)
return(-1);
Daniel Veillard
committed
/*
* First quick algorithm for ASCII range
*/
if (space)
while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillard
committed
if (((*cur >= 'a') && (*cur <= 'z')) ||
((*cur >= 'A') && (*cur <= 'Z')) ||
((*cur >= '0') && (*cur <= '9')) ||
(*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
cur++;
else
goto try_complex;
while (((*cur >= 'a') && (*cur <= 'z')) ||
((*cur >= 'A') && (*cur <= 'Z')) ||
((*cur >= '0') && (*cur <= '9')) ||
(*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
cur++;
if (space)
while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillard
committed
if (*cur == 0)
return(0);
try_complex:
/*
* Second check for chars outside the ASCII range
*/
cur = value;
c = CUR_SCHAR(cur, l);
if (space) {
while (IS_BLANK(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
}
William M. Brack
committed
if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
(c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillard
committed
return(1);
cur += l;
c = CUR_SCHAR(cur, l);
William M. Brack
committed
while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
(c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillard
committed
cur += l;
c = CUR_SCHAR(cur, l);
}
if (space) {
while (IS_BLANK(c)) {
cur += l;
c = CUR_SCHAR(cur, l);
}
}
if (c != 0)
return(1);
return(0);
}
#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard
committed
/************************************************************************
* *
* Allocation and deallocation of basic structures *
* *
************************************************************************/
/**
* xmlSetBufferAllocationScheme:
* @scheme: allocation method to use
*
* Set the buffer allocation method. Types are
* XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
* XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
* improves performance
*/
void
xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
Daniel Veillard
committed
if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
(scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
(scheme == XML_BUFFER_ALLOC_HYBRID))
Daniel Veillard
committed
xmlBufferAllocScheme = scheme;
}
/**
* xmlGetBufferAllocationScheme:
*
* Types are
* XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
* XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
* XML_BUFFER_ALLOC_HYBRID - use exact sizes on small strings to keep memory usage tight
* in normal usage, and doubleit on large strings to avoid
* pathological performance.
*
* Returns the current allocation scheme
*/
xmlBufferAllocationScheme
xmlGetBufferAllocationScheme(void) {
return(xmlBufferAllocScheme);
}
/**
* xmlNewNs:
* @node: the element carrying the namespace
* @href: the URI associated
* @prefix: the prefix for the namespace
*
* Creation of a new Namespace. This function will refuse to create
* a namespace with a similar prefix than an existing one present on this
* node.
* Note that for a default namespace, @prefix should be NULL.
*
* We use href==NULL in the case of an element creation where the namespace
* was not defined.
* Returns a new namespace pointer or NULL
*/
xmlNsPtr
xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
xmlNsPtr cur;
if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
return(NULL);
if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
/* xml namespace is predefined, no need to add it */
if (xmlStrEqual(href, XML_XML_NAMESPACE))
return(NULL);
/*
* Problem, this is an attempt to bind xml prefix to a wrong
* namespace, which breaks
* Namespace constraint: Reserved Prefixes and Namespace Names
* from XML namespace. But documents authors may not care in
* their context so let's proceed.
*/
}
/*
* Allocate a new Namespace and fill the fields.
*/
cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
if (cur == NULL) {
xmlTreeErrMemory("building namespace");
return(NULL);
}
memset(cur, 0, sizeof(xmlNs));
cur->type = XML_LOCAL_NAMESPACE;
if (href != NULL)
cur->href = xmlStrdup(href);
cur->prefix = xmlStrdup(prefix);
/*
* Add it at the end to preserve parsing order ...
* and checks for existing use of the prefix
*/
if (node != NULL) {
if (node->nsDef == NULL) {
node->nsDef = cur;
} else {
xmlNsPtr prev = node->nsDef;
if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
(xmlStrEqual(prev->prefix, cur->prefix))) {
xmlFreeNs(cur);
return(NULL);
}
while (prev->next != NULL) {
prev = prev->next;
if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
(xmlStrEqual(prev->prefix, cur->prefix))) {
xmlFreeNs(cur);
return(NULL);
}
}
prev->next = cur;
}
}
return(cur);
}
/**
* xmlSetNs:
* @node: a node in the document
* @ns: a namespace pointer
*
* Associate a namespace to a node, a posteriori.
*/
void
xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
if (node == NULL) {
#ifdef DEBUG_TREE
xmlGenericError(xmlGenericErrorContext,
"xmlSetNs: node == NULL\n");
#endif
return;
}
if ((node->type == XML_ELEMENT_NODE) ||
(node->type == XML_ATTRIBUTE_NODE))
node->ns = ns;
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
}
/**
* xmlFreeNs:
* @cur: the namespace pointer
*
* Free up the structures associated to a namespace
*/
void
xmlFreeNs(xmlNsPtr cur) {
if (cur == NULL) {
#ifdef DEBUG_TREE
xmlGenericError(xmlGenericErrorContext,
"xmlFreeNs : ns == NULL\n");
#endif
return;
}
if (cur->href != NULL) xmlFree((char *) cur->href);
if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
xmlFree(cur);
}
/**
* xmlFreeNsList:
* @cur: the first namespace pointer
*
* Free up all the structures associated to the chained namespaces.
*/
void
xmlFreeNsList(xmlNsPtr cur) {
xmlNsPtr next;
if (cur == NULL) {
#ifdef DEBUG_TREE
xmlGenericError(xmlGenericErrorContext,
"xmlFreeNsList : ns == NULL\n");
#endif
return;
}
while (cur != NULL) {
next = cur->next;
xmlFreeNs(cur);
cur = next;
}
}
/**
* xmlNewDtd:
* @doc: the document pointer
* @name: the DTD name
* @ExternalID: the external ID
* @SystemID: the system ID
*
* Creation of a new DTD for the external subset. To create an
* internal subset, use xmlCreateIntSubset().
*
* Returns a pointer to the new DTD structure
*/
xmlDtdPtr
xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
const xmlChar *ExternalID, const xmlChar *SystemID) {
xmlDtdPtr cur;
if ((doc != NULL) && (doc->extSubset != NULL)) {
#ifdef DEBUG_TREE
xmlGenericError(xmlGenericErrorContext,
"xmlNewDtd(%s): document %s already have a DTD %s\n",
/* !!! */ (char *) name, doc->name,
/* !!! */ (char *)doc->extSubset->name);
#endif
return(NULL);
}
/*
* Allocate a new DTD and fill the fields.
*/
cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
if (cur == NULL) {
xmlTreeErrMemory("building DTD");
return(NULL);
}
memset(cur, 0 , sizeof(xmlDtd));
cur->type = XML_DTD_NODE;
if (name != NULL)
cur->name = xmlStrdup(name);
cur->ExternalID = xmlStrdup(ExternalID);
cur->SystemID = xmlStrdup(SystemID);
if (doc != NULL)
doc->extSubset = cur;
cur->doc = doc;
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
return(cur);
}
/**
* xmlGetIntSubset:
* @doc: the document pointer
*
* Get the internal subset of a document
* Returns a pointer to the DTD structure or NULL if not found
*/
xmlDtdPtr
xmlNodePtr cur;
if (doc == NULL)
return(NULL);
cur = doc->children;
while (cur != NULL) {
if (cur->type == XML_DTD_NODE)
return((xmlDtdPtr) cur);
cur = cur->next;
}
return((xmlDtdPtr) doc->intSubset);
}
/**
* xmlCreateIntSubset:
* @doc: the document pointer
* @name: the DTD name
* @SystemID: the system ID
*
* Create the internal subset of a document
* Returns a pointer to the new DTD structure
*/
xmlDtdPtr
xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
const xmlChar *ExternalID, const xmlChar *SystemID) {
xmlDtdPtr cur;
if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
#ifdef DEBUG_TREE
xmlGenericError(xmlGenericErrorContext,
"xmlCreateIntSubset(): document %s already have an internal subset\n",
doc->name);
#endif
return(NULL);
}
/*
* Allocate a new DTD and fill the fields.
*/
cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
if (cur == NULL) {
xmlTreeErrMemory("building internal subset");
return(NULL);
}
memset(cur, 0, sizeof(xmlDtd));
cur->type = XML_DTD_NODE;
if (name != NULL) {
cur->name = xmlStrdup(name);
if (cur->name == NULL) {
xmlTreeErrMemory("building internal subset");
xmlFree(cur);
return(NULL);
}
}
if (ExternalID != NULL) {
cur->ExternalID = xmlStrdup(ExternalID);
if (cur->ExternalID == NULL) {
xmlTreeErrMemory("building internal subset");
if (cur->name != NULL)
xmlFree((char *)cur->name);
xmlFree(cur);
return(NULL);
}
}
if (SystemID != NULL) {
cur->SystemID = xmlStrdup(SystemID);
if (cur->SystemID == NULL) {
xmlTreeErrMemory("building internal subset");
if (cur->name != NULL)
xmlFree((char *)cur->name);
if (cur->ExternalID != NULL)
xmlFree((char *)cur->ExternalID);
xmlFree(cur);
return(NULL);
}