Roll libxml from c444c96e to 9bce9dbb
2024-03-26 wellnhofer@aevum.de valid: Report malloc failure in xmlValidateOneElement
2024-03-26 wellnhofer@aevum.de fuzz: Restrict input size of API fuzzer
2024-03-26 wellnhofer@aevum.de fuzz: Restrict number of copies in API fuzzer
2024-03-26 wellnhofer@aevum.de html: Use binary search in htmlEntityValueLookup
2024-03-25 wellnhofer@aevum.de tree: Work on documentation
2024-03-24 wellnhofer@aevum.de fuzz: Enable float-divide-by-zero on OSS-Fuzz
2024-03-24 wellnhofer@aevum.de xinclude: Report malloc failure in xmlXIncludeAddNode
2024-03-22 wellnhofer@aevum.de tree: Fix uninitialized value in xmlSearchNsSafe
2024-03-22 wellnhofer@aevum.de ci: Support ASan in Docker container
2024-03-22 wellnhofer@aevum.de ci: Show config.log if configuration failed
2024-03-22 wellnhofer@aevum.de ci: Remove Python 2 job, update C89 job
2024-03-22 wellnhofer@aevum.de doc: Update Docker CI instructions
2024-03-22 wellnhofer@aevum.de ci: Update Docker container to Ubuntu 23.10
2024-03-22 wellnhofer@aevum.de ci: Add meson to Docker container
2024-03-22 wellnhofer@aevum.de fuzz: Fix namespaces after xmlDOMWrapRemoveNode
2024-03-22 wellnhofer@aevum.de SAX2: Report malloc failure in xmlSAX2AttributeNs
2024-03-22 wellnhofer@aevum.de xinclude: Report malloc failures in xmlXIncludeIncludeNode
2024-03-22 wellnhofer@aevum.de tree: Fix uninitialized value in xmlSearchNsByHrefSafe
2024-03-20 wellnhofer@aevum.de fuzz: Enable API fuzzer on OSS-Fuzz
2024-03-20 wellnhofer@aevum.de fuzz: Reorder API fuzzer ops
2024-03-20 wellnhofer@aevum.de fuzz: Check text nodes after merging
2024-03-19 wellnhofer@aevum.de valid: Check for NULL node->name in xmlSnprintfElements
2024-03-18 wellnhofer@aevum.de io: Allocate output buffer with XML_BUFFER_ALLOC_IO
2024-03-18 wellnhofer@aevum.de encoding: Don't shrink input too early in xmlCharEncOutput
2024-03-18 wellnhofer@aevum.de tree: Report malloc failures in attribute setters
2024-03-18 wellnhofer@aevum.de xinclude: Set errNo in xmlXIncludeErrMemory
2024-03-17 wellnhofer@aevum.de tree: Introduce xmlSearchNsSafe
2024-03-17 wellnhofer@aevum.de Revert "tree: Allocate XML namespace statically"
2024-03-17 wellnhofer@aevum.de save: Check for NULL node->name in xhtmlIsEmpty
2024-03-17 wellnhofer@aevum.de schemas: Fix ADD_ANNOTATION
2024-03-17 wellnhofer@aevum.de xmlreader: Fix memory leak in xmlTextReaderFreeProp
2024-03-16 wellnhofer@aevum.de valid: Deprecate internal validation functions
2024-03-16 wellnhofer@aevum.de fuzz: Move fuzzer options to environment variable
2024-03-15 wellnhofer@aevum.de fuzz: Add OSS-Fuzz build.sh
2024-03-15 wellnhofer@aevum.de fuzz: Add some comments in api.c
2024-02-29 wellnhofer@aevum.de fuzz: New tree API fuzzer
2024-03-15 wellnhofer@aevum.de tree: Tighten source doc check in xmlDOMWrapAdoptNode
2024-03-14 wellnhofer@aevum.de tree: Check destParent->doc in xmlDOMWrapCloneNode
2024-03-13 wellnhofer@aevum.de tree: Switch to xmlNodeSetDoc in xmlDOMWrapAdoptNode
2024-03-13 wellnhofer@aevum.de tree: Fix tree iteration in xmlDOMWrapRemoveNode
2024-03-12 wellnhofer@aevum.de tree: Don't abort early if malloc fails in DOM functions
2024-03-12 wellnhofer@aevum.de tree: Fix reallocation in xmlDOMWrapNSNormAddNsMapItem2
2024-03-12 wellnhofer@aevum.de tree: Set parent->last early in xmlDOMWrapCloneNode
2024-03-12 wellnhofer@aevum.de tree: Declare namespace on clone in xmlDOMWrapCloneNode
2024-03-12 wellnhofer@aevum.de tree: Don't free linked DOM namespaces in error case
2024-03-12 wellnhofer@aevum.de tree: Report malloc failure in xmlDOMWrapCloneNode
2024-03-11 wellnhofer@aevum.de tree: Refactor text node updates
2024-03-11 wellnhofer@aevum.de tree: Refactor node insertion
2024-03-11 wellnhofer@aevum.de tree: Refactor element creation and parsing of attribute values
2024-03-05 wellnhofer@aevum.de tree: Simplify xmlNodeGetContent, xmlBufGetNodeContent
2024-03-11 wellnhofer@aevum.de buf: Don't use default buffer size for small strings
2024-03-08 wellnhofer@aevum.de valid: Set document on dummmy element declaration
2024-03-07 wellnhofer@aevum.de tree: Work on documentation
2024-03-06 wellnhofer@aevum.de string: Fix xmlStrncatNew(NULL, "")
2024-03-05 wellnhofer@aevum.de malloc-fail: Stop using xmlSplitQName2
2024-03-05 wellnhofer@aevum.de malloc-fail: Report in xmlAddAttributeDecl
2024-03-05 wellnhofer@aevum.de malloc-fail: Fix erroneous report in xmlNodeGetBaseSafe
2024-03-04 wellnhofer@aevum.de malloc-fail: Avoid use-after-free in xmlAddChild
2024-03-04 wellnhofer@aevum.de malloc-fail: Fix memory leak in xmlNewNodeEatName
2024-03-04 wellnhofer@aevum.de malloc-fail: Check for NULL pointer in xmlSaveNotation*
2024-03-04 wellnhofer@aevum.de malloc-fail: Fix use-after-free in xmlBufBackToBuffer
2024-03-05 wellnhofer@aevum.de entities: Don't allow null name in xmlNewEntity
2024-03-05 wellnhofer@aevum.de entities: Check for illegal entity types in xmlAddEntity
2024-03-06 wellnhofer@aevum.de io: Report more malloc failures when writing to output buffer
2024-03-06 wellnhofer@aevum.de html: Fix quadratic behavior in htmlNodeDump
2024-03-05 wellnhofer@aevum.de save: Report malloc failure in xmlAttrSerializeTxtContent
2024-03-04 wellnhofer@aevum.de save: Cast return code of xmlBufNodeDump
2024-03-05 wellnhofer@aevum.de save: Check for output buffer errors
2024-03-03 wellnhofer@aevum.de save: Add range check for level in xmlNodeDump
2024-03-15 wellnhofer@aevum.de valid: Check for NULL text content in xmlValidateOneElement
2024-03-14 wellnhofer@aevum.de valid: Check for elem->name in xmlIsID
2024-03-06 wellnhofer@aevum.de valid: Fix some return codes after errors
2024-03-05 wellnhofer@aevum.de valid: Eliminate xmlCtxtGetDtdElementDesc
2024-03-05 wellnhofer@aevum.de valid: Report malloc failure in legacy DTD serialization
2024-03-05 wellnhofer@aevum.de valid: Fix hash removal in xmlRemoveRef
2024-03-05 wellnhofer@aevum.de valid: Don't report errors with null context
2024-03-02 wellnhofer@aevum.de valid: Remove id before updating attribute type
2024-03-01 wellnhofer@aevum.de valid: Fix id handling in xmlValidateDtd
2024-03-02 wellnhofer@aevum.de valid: Reset attribute in xmlFreeID
2024-03-01 wellnhofer@aevum.de valid: Rework checks in xmlValidateOneElement
2024-02-29 wellnhofer@aevum.de valid: Check element type in xmlIsID
2024-02-29 wellnhofer@aevum.de valid: Change error code to XML_ERR_ARGUMENT
2024-03-08 wellnhofer@aevum.de tree: Check return value of xmlNodeAddContent
2024-03-07 wellnhofer@aevum.de tree: Fix error return in xmlGetPropNodeValueInternal
2024-03-07 wellnhofer@aevum.de tree: Prefer xmlGetPropNodeInternal over xmlHasNsProp
2024-03-06 wellnhofer@aevum.de tree: Report malloc failure in xmlAddNextSibling
2024-03-02 wellnhofer@aevum.de tree: Rewrite xmlSetTreeDoc
2024-03-05 wellnhofer@aevum.de tree: Remove more unused node types
2024-03-06 wellnhofer@aevum.de tree: Report more malloc failures
2024-03-04 wellnhofer@aevum.de tree: Fix adding ids in xmlNewPropInternal
2024-02-29 wellnhofer@aevum.de valid: Rework xmlAddID
2024-03-05 wellnhofer@aevum.de tree: Improve argument check in xmlTextConcat
2024-03-05 wellnhofer@aevum.de tree: Remove unused node types
2024-03-05 wellnhofer@aevum.de tree: Make namespace comparison more consistent
2024-03-05 wellnhofer@aevum.de tree: Don't allow NULL name in xmlSetNsProp
2024-03-04 wellnhofer@aevum.de tree: Allocate XML namespace statically
2024-03-05 wellnhofer@aevum.de tree: Rework xmlNodeListGetString
2024-02-28 wellnhofer@aevum.de tree: Rework xmlTextMerge
2024-02-28 wellnhofer@aevum.de tree: Rework xmlNodeSetName
2024-02-27 wellnhofer@aevum.de tree: Simplify xmlAddChild with text parent
2024-02-27 wellnhofer@aevum.de tree: Don't allow misuse of xmlAddChild
2024-02-27 wellnhofer@aevum.de tree: Fix xmlAddPropSibling with duplicate attributes
2024-02-27 wellnhofer@aevum.de tree: Fix indentation in xmlAddPropSibling
2024-02-27 wellnhofer@aevum.de tree: Fix xmlAddSibling with last sibling
2024-02-27 wellnhofer@aevum.de tree: Move type check in xmlAddChild
2024-02-23 wellnhofer@aevum.de tree: Fix xmlDocSetRootElement with multiple top-level elements
2024-02-22 wellnhofer@aevum.de tree: Only allow elements in xmlDocSetRootElement
2024-02-22 wellnhofer@aevum.de tree: Disallow setting content of entity reference nodes
2024-02-22 wellnhofer@aevum.de tree: Rework xmlReconciliateNs
2024-02-22 wellnhofer@aevum.de tree: Unlink DTD in xmlStaticCopyNodeList
2024-02-22 wellnhofer@aevum.de tree: Unlink DTD in xmlFreeNodeList
2024-03-12 wellnhofer@aevum.de parser: Fix detection of duplicate attributes in XML namespace
2024-03-10 wellnhofer@aevum.de fuzz: Improve README
2024-03-03 wellnhofer@aevum.de catalog: Fetch XML catalog before dumping
2024-03-02 bgilbert@backtick.net schemas: fix spurious warning about truncated snprintf output
2024-02-29 maks.mishinFZ@gmail.com xmlschemastypes: Remove unreachable if statement
2024-02-29 maks.mishinFZ@gmail.com relaxng: Remove useless if statement
2024-02-26 wellnhofer@aevum.de xmlreader: Fix xmlTextReaderConstEncoding
2024-02-26 wellnhofer@aevum.de html: Regression test for #696
2024-02-21 wellnhofer@aevum.de tree: Check for integer overflow in xmlStringGetNodeList
2024-02-20 wellnhofer@aevum.de SAX2: Report malloc failure in xmlCheckDefaultedAttributes
2024-02-19 wellnhofer@aevum.de http: Improve error message for HTTPS redirects
2024-02-16 wellnhofer@aevum.de save: Don't write directly to internal buffer
2024-02-14 wellnhofer@aevum.de dict: Include unistd.h for getentropy
Bug: 934413
Change-Id: I136270e532c21e40bc880509603308c6e5543bff
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5403594
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1281330}
NOKEYCHECK=True
GitOrigin-RevId: 63d2d18490fbe995343561fcd603369156efb846
diff --git a/README.chromium b/README.chromium
index 291f832..6e09d2d 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,6 +1,6 @@
Name: libxml
URL: http://xmlsoft.org
-Version: c444c96e20253e5996f4209a123b96a6c273dac6
+Version: 9bce9dbb19987224905f40e64fe227c0c981fa3a
CPEPrefix: cpe:/a:xmlsoft:libxml2:2.12.5
License: MIT
License File: src/Copyright
diff --git a/chromium/remove-getentropy.patch b/chromium/remove-getentropy.patch
index 7d19136..80f65ed 100644
--- a/chromium/remove-getentropy.patch
+++ b/chromium/remove-getentropy.patch
@@ -5,25 +5,29 @@
generation behavior before a recent libxml upstream patch.
diff --git a/dict.c b/dict.c
-index 5c9f3aa2..7a492895 100644
+index c843bb7b..96435d52 100644
--- a/dict.c
+++ b/dict.c
-@@ -24,14 +24,10 @@
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
--#ifdef HAVE_SYS_RANDOM_H
--#include <sys/random.h>
--#endif
-
+@@ -909,17 +909,12 @@ xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
#ifdef _WIN32
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
--#include <bcrypt.h>
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+- #include <bcrypt.h>
+ #elif defined(HAVE_GETENTROPY)
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+- #ifdef HAVE_SYS_RANDOM_H
+- #include <sys/random.h>
+- #endif
+-#else
+- #include <time.h>
#endif
++#include <time.h>
- #include "private/dict.h"
-@@ -926,29 +922,6 @@ xmlInitRandom(void) {
+ static xmlMutex xmlRngMutex;
+
+@@ -931,29 +926,6 @@ xmlInitRandom(void) {
xmlInitMutex(&xmlRngMutex);
{
@@ -53,7 +57,7 @@
int var;
globalRngState[0] =
-@@ -957,7 +930,6 @@ xmlInitRandom(void) {
+@@ -962,7 +934,6 @@ xmlInitRandom(void) {
globalRngState[1] =
HASH_ROL((unsigned) ((size_t) &xmlRngMutex & 0xFFFFFFFF), 16) ^
HASH_ROL((unsigned) ((size_t) &var & 0xFFFFFFFF), 24);
diff --git a/mac/config.h b/mac/config.h
index 59b8e8c..0ea06ac 100644
--- a/mac/config.h
+++ b/mac/config.h
@@ -22,13 +22,13 @@
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
-/* Define to 1 if you have the `ftime' function. */
+/* Define to 1 if you have the 'ftime' function. */
#define HAVE_FTIME 1
-/* Define to 1 if you have the `getentropy' function. */
+/* Define to 1 if you have the 'getentropy' function. */
#define HAVE_GETENTROPY 1
-/* Define to 1 if you have the `gettimeofday' function. */
+/* Define to 1 if you have the 'gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the <glob.h> header file. */
@@ -37,7 +37,7 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
-/* Define to 1 if you have the `isascii' function. */
+/* Define to 1 if you have the 'isascii' function. */
#define HAVE_ISASCII 1
/* Define if history library is there (-lhistory) */
@@ -49,10 +49,10 @@
/* Define to 1 if you have the <lzma.h> header file. */
/* #undef HAVE_LZMA_H */
-/* Define to 1 if you have the `mmap' function. */
+/* Define to 1 if you have the 'mmap' function. */
#define HAVE_MMAP 1
-/* Define to 1 if you have the `munmap' function. */
+/* Define to 1 if you have the 'munmap' function. */
#define HAVE_MUNMAP 1
/* mmap() is no good without munmap() */
@@ -75,7 +75,7 @@
/* Have shl_load based dso */
/* #undef HAVE_SHLLOAD */
-/* Define to 1 if you have the `stat' function. */
+/* Define to 1 if you have the 'stat' function. */
#define HAVE_STAT 1
/* Define to 1 if you have the <stdint.h> header file. */
@@ -147,7 +147,7 @@
/* Define to the version of this package. */
#define PACKAGE_VERSION "2.13.0"
-/* Define to 1 if all of the C90 standard headers exist (not just the ones
+/* Define to 1 if all of the C89 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#define STDC_HEADERS 1
diff --git a/src/HTMLparser.c b/src/HTMLparser.c
index 30b0fc8..b1271e6 100644
--- a/src/HTMLparser.c
+++ b/src/HTMLparser.c
@@ -2011,6 +2011,14 @@
return(NULL);
}
+static int
+htmlCompareEntityDesc(const void *vkey, const void *vdesc) {
+ const unsigned *key = vkey;
+ const htmlEntityDesc *desc = vdesc;
+
+ return((int) *key - (int) desc->value);
+}
+
/**
* htmlEntityValueLookup:
* @value: the entity's unicode value
@@ -2023,17 +2031,14 @@
*/
const htmlEntityDesc *
htmlEntityValueLookup(unsigned int value) {
- unsigned int i;
+ const htmlEntityDesc *desc;
+ size_t nmemb;
- for (i = 0;i < (sizeof(html40EntitiesTable)/
- sizeof(html40EntitiesTable[0]));i++) {
- if (html40EntitiesTable[i].value >= value) {
- if (html40EntitiesTable[i].value > value)
- break;
- return((htmlEntityDescPtr) &html40EntitiesTable[i]);
- }
- }
- return(NULL);
+ nmemb = sizeof(html40EntitiesTable) / sizeof(html40EntitiesTable[0]);
+ desc = bsearch(&value, html40EntitiesTable, nmemb, sizeof(htmlEntityDesc),
+ htmlCompareEntityDesc);
+
+ return(desc);
}
/**
diff --git a/src/HTMLtree.c b/src/HTMLtree.c
index 89d6181..acdde75 100644
--- a/src/HTMLtree.c
+++ b/src/HTMLtree.c
@@ -421,18 +421,18 @@
htmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur,
int format) {
size_t use;
- int ret;
+ size_t ret;
xmlOutputBufferPtr outbuf;
if (cur == NULL) {
- return (-1);
+ return ((size_t) -1);
}
if (buf == NULL) {
- return (-1);
+ return ((size_t) -1);
}
outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
if (outbuf == NULL)
- return (-1);
+ return ((size_t) -1);
memset(outbuf, 0, sizeof(xmlOutputBuffer));
outbuf->buffer = buf;
outbuf->encoder = NULL;
@@ -443,8 +443,11 @@
use = xmlBufUse(buf);
htmlNodeDumpFormatOutput(outbuf, doc, cur, NULL, format);
+ if (outbuf->error)
+ ret = (size_t) -1;
+ else
+ ret = xmlBufUse(buf) - use;
xmlFree(outbuf);
- ret = xmlBufUse(buf) - use;
return (ret);
}
@@ -472,6 +475,7 @@
if (buffer == NULL)
return(-1);
+ xmlBufSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT);
ret = htmlBufNodeDumpFormat(buffer, doc, cur, 1);
xmlBufBackToBuffer(buffer);
@@ -551,32 +555,32 @@
if ((mem == NULL) || (size == NULL))
return;
- if (cur == NULL) {
- *mem = NULL;
- *size = 0;
+ *mem = NULL;
+ *size = 0;
+ if (cur == NULL)
return;
- }
encoding = (const char *) htmlGetMetaEncoding(cur);
handler = htmlFindOutputEncoder(encoding);
buf = xmlAllocOutputBufferInternal(handler);
- if (buf == NULL) {
- *mem = NULL;
- *size = 0;
+ if (buf == NULL)
return;
- }
htmlDocContentDumpFormatOutput(buf, cur, NULL, format);
xmlOutputBufferFlush(buf);
- if (buf->conv != NULL) {
- *size = xmlBufUse(buf->conv);
- *mem = xmlStrndup(xmlBufContent(buf->conv), *size);
- } else {
- *size = xmlBufUse(buf->buffer);
- *mem = xmlStrndup(xmlBufContent(buf->buffer), *size);
+
+ if (!buf->error) {
+ if (buf->conv != NULL) {
+ *size = xmlBufUse(buf->conv);
+ *mem = xmlStrndup(xmlBufContent(buf->conv), *size);
+ } else {
+ *size = xmlBufUse(buf->buffer);
+ *mem = xmlStrndup(xmlBufContent(buf->buffer), *size);
+ }
}
- (void)xmlOutputBufferClose(buf);
+
+ xmlOutputBufferClose(buf);
}
/**
@@ -623,15 +627,15 @@
xmlOutputBufferWriteString(buf, (const char *)cur->name);
if (cur->ExternalID != NULL) {
xmlOutputBufferWriteString(buf, " PUBLIC ");
- xmlBufWriteQuotedString(buf->buffer, cur->ExternalID);
+ xmlOutputBufferWriteQuotedString(buf, cur->ExternalID);
if (cur->SystemID != NULL) {
xmlOutputBufferWriteString(buf, " ");
- xmlBufWriteQuotedString(buf->buffer, cur->SystemID);
+ xmlOutputBufferWriteQuotedString(buf, cur->SystemID);
}
} else if (cur->SystemID != NULL &&
xmlStrcmp(cur->SystemID, BAD_CAST "about:legacy-compat")) {
xmlOutputBufferWriteString(buf, " SYSTEM ");
- xmlBufWriteQuotedString(buf->buffer, cur->SystemID);
+ xmlOutputBufferWriteQuotedString(buf, cur->SystemID);
}
xmlOutputBufferWriteString(buf, ">\n");
}
@@ -691,13 +695,13 @@
escaped = xmlURIEscapeStr(tmp,
BAD_CAST "\"#$%&+,/:;<=>?@[\\]^`{|}");
if (escaped != NULL) {
- xmlBufWriteQuotedString(buf->buffer, escaped);
+ xmlOutputBufferWriteQuotedString(buf, escaped);
xmlFree(escaped);
} else {
buf->error = XML_ERR_NO_MEMORY;
}
} else {
- xmlBufWriteQuotedString(buf->buffer, value);
+ xmlOutputBufferWriteQuotedString(buf, value);
}
xmlFree(value);
} else {
diff --git a/src/SAX2.c b/src/SAX2.c
index f102bb6..30bff09 100644
--- a/src/SAX2.c
+++ b/src/SAX2.c
@@ -812,10 +812,6 @@
doc->dict = ctxt->dict;
xmlDictReference(doc->dict);
}
- if (xmlTreeEnsureXMLDecl(doc) == NULL) {
- xmlSAX2ErrMemory(ctxt);
- return;
- }
}
if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
(ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
@@ -846,17 +842,7 @@
doc = ctxt->myDoc;
if ((doc != NULL) && (doc->encoding == NULL)) {
- const xmlChar *encoding = NULL;
-
- if ((ctxt->input->flags & XML_INPUT_USES_ENC_DECL) ||
- (ctxt->input->flags & XML_INPUT_AUTO_ENCODING)) {
- /* Preserve encoding exactly */
- encoding = ctxt->encoding;
- } else if ((ctxt->input->buf) && (ctxt->input->buf->encoder)) {
- encoding = BAD_CAST ctxt->input->buf->encoder->name;
- } else if (ctxt->input->flags & XML_INPUT_HAS_ENCODING) {
- encoding = BAD_CAST "UTF-8";
- }
+ const xmlChar *encoding = xmlGetActualEncoding(ctxt);
if (encoding != NULL) {
doc->encoding = xmlStrdup(encoding);
@@ -1114,7 +1100,11 @@
}
if (ns != NULL) {
- namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns);
+ int res;
+
+ res = xmlSearchNsSafe(ctxt->node, ns, &namespace);
+ if (res < 0)
+ xmlSAX2ErrMemory(ctxt);
if (namespace == NULL) {
xmlNsErrMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
@@ -1154,20 +1144,8 @@
}
if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
- xmlNodePtr tmp;
-
- if ((value != NULL) && (value[0] != 0)) {
- ret->children = xmlStringGetNodeList(ctxt->myDoc, value);
- if (ret->children == NULL)
- xmlSAX2ErrMemory(ctxt);
- }
- tmp = ret->children;
- while (tmp != NULL) {
- tmp->parent = (xmlNodePtr) ret;
- if (tmp->next == NULL)
- ret->last = tmp;
- tmp = tmp->next;
- }
+ if (xmlNodeParseContent((xmlNodePtr) ret, value, INT_MAX) < 0)
+ xmlSAX2ErrMemory(ctxt);
} else if (value != NULL) {
ret->children = xmlNewDocText(ctxt->myDoc, value);
if (ret->children == NULL) {
@@ -1304,8 +1282,10 @@
if (attr->prefix != NULL) {
fulln = xmlStrdup(attr->prefix);
- fulln = xmlStrcat(fulln, BAD_CAST ":");
- fulln = xmlStrcat(fulln, attr->name);
+ if (fulln != NULL)
+ fulln = xmlStrcat(fulln, BAD_CAST ":");
+ if (fulln != NULL)
+ fulln = xmlStrcat(fulln, attr->name);
} else {
fulln = xmlStrdup(attr->name);
}
@@ -1509,6 +1489,8 @@
xmlAddChild(parent, ret);
if (!ctxt->html) {
+ int res;
+
/*
* Insert all the defaulted attributes from the DTD especially
* namespaces
@@ -1539,9 +1521,14 @@
* Search the namespace, note that since the attributes have been
* processed, the local namespaces are available.
*/
- ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
- if ((ns == NULL) && (parent != NULL))
- ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
+ res = xmlSearchNsSafe(ret, prefix, &ns);
+ if (res < 0)
+ xmlSAX2ErrMemory(ctxt);
+ if ((ns == NULL) && (parent != NULL)) {
+ res = xmlSearchNsSafe(parent, prefix, &ns);
+ if (res < 0)
+ xmlSAX2ErrMemory(ctxt);
+ }
if ((prefix != NULL) && (ns == NULL)) {
xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
"Namespace prefix %s is not defined\n",
@@ -1793,7 +1780,11 @@
if (prefix != NULL) {
namespace = xmlParserNsLookupSax(ctxt, prefix);
if ((namespace == NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
- namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, prefix);
+ int res;
+
+ res = xmlSearchNsSafe(ctxt->node, prefix, &namespace);
+ if (res < 0)
+ xmlSAX2ErrMemory(ctxt);
}
}
@@ -1856,18 +1847,9 @@
tmp->parent = (xmlNodePtr) ret;
}
} else if (valueend > value) {
- ret->children = xmlStringLenGetNodeList(ctxt->myDoc, value,
- valueend - value);
- if (ret->children == NULL)
+ if (xmlNodeParseContent((xmlNodePtr) ret, value,
+ valueend - value) < 0)
xmlSAX2ErrMemory(ctxt);
- tmp = ret->children;
- while (tmp != NULL) {
- tmp->doc = ret->doc;
- tmp->parent = (xmlNodePtr) ret;
- if (tmp->next == NULL)
- ret->last = tmp;
- tmp = tmp->next;
- }
}
} else if (value != NULL) {
xmlNodePtr tmp;
@@ -1921,7 +1903,9 @@
xmlChar *fullname;
fullname = xmlBuildQName(localname, prefix, fn, 50);
- if (fullname != NULL) {
+ if (fullname == NULL) {
+ xmlSAX2ErrMemory(ctxt);
+ } else {
ctxt->vctxt.valid = 1;
nvalnorm = xmlValidCtxtNormalizeAttributeValue(
&ctxt->vctxt, ctxt->myDoc,
@@ -2183,7 +2167,11 @@
if ((URI != NULL) && (ret->ns == NULL)) {
ret->ns = xmlParserNsLookupSax(ctxt, prefix);
if ((ret->ns == NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
- ret->ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
+ int res;
+
+ res = xmlSearchNsSafe(ret, prefix, &ret->ns);
+ if (res < 0)
+ xmlSAX2ErrMemory(ctxt);
}
if (ret->ns == NULL) {
ns = xmlNewNs(ret, NULL, prefix);
diff --git a/src/buf.c b/src/buf.c
index 7e860f7..f9f59b2 100644
--- a/src/buf.c
+++ b/src/buf.c
@@ -195,8 +195,16 @@
if (buf->error)
return(NULL);
- ret = buf->content;
+ if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
+ (buf->content != buf->contentIO)) {
+ ret = xmlStrndup(buf->content, buf->use);
+ xmlFree(buf->contentIO);
+ } else {
+ ret = buf->content;
+ }
+
buf->content = NULL;
+ buf->contentIO = NULL;
buf->size = 0;
buf->use = 0;
UPDATE_COMPAT(buf);
@@ -743,8 +751,7 @@
* Add a string range to an XML buffer. if len == -1, the length of
* str is recomputed.
*
- * Returns 0 successful, a positive error code number otherwise
- * and -1 in case of internal or API error.
+ * Returns 0 if successful, -1 in case of error.
*/
int
xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
@@ -781,10 +788,8 @@
return(-1);
}
}
- if (!xmlBufResize(buf, needSize)){
- xmlBufMemoryError(buf);
- return XML_ERR_NO_MEMORY;
- }
+ if (!xmlBufResize(buf, needSize))
+ return(-1);
}
memmove(&buf->content[buf->use], str, len);
@@ -814,72 +819,6 @@
}
/**
- * xmlBufCCat:
- * @buf: the buffer to dump
- * @str: the C char string
- *
- * Append a zero terminated C string to an XML buffer.
- *
- * Returns 0 successful, a positive error code number otherwise
- * and -1 in case of internal or API error.
- */
-int
-xmlBufCCat(xmlBufPtr buf, const char *str) {
- return xmlBufCat(buf, (const xmlChar *) str);
-}
-
-/**
- * xmlBufWriteQuotedString:
- * @buf: the XML buffer output
- * @string: the string to add
- *
- * routine which manage and grows an output buffer. This one writes
- * a quoted or double quoted #xmlChar string, checking first if it holds
- * quote or double-quotes internally
- *
- * Returns 0 if successful, a positive error code number otherwise
- * and -1 in case of internal or API error.
- */
-int
-xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
- const xmlChar *cur, *base;
- if ((buf == NULL) || (buf->error))
- return(-1);
- CHECK_COMPAT(buf)
- if (xmlStrchr(string, '\"')) {
- if (xmlStrchr(string, '\'')) {
- xmlBufCCat(buf, "\"");
- base = cur = string;
- while(*cur != 0){
- if(*cur == '"'){
- if (base != cur)
- xmlBufAdd(buf, base, cur - base);
- xmlBufAdd(buf, BAD_CAST """, 6);
- cur++;
- base = cur;
- }
- else {
- cur++;
- }
- }
- if (base != cur)
- xmlBufAdd(buf, base, cur - base);
- xmlBufCCat(buf, "\"");
- }
- else{
- xmlBufCCat(buf, "\'");
- xmlBufCat(buf, string);
- xmlBufCCat(buf, "\'");
- }
- } else {
- xmlBufCCat(buf, "\"");
- xmlBufCat(buf, string);
- xmlBufCCat(buf, "\"");
- }
- return(0);
-}
-
-/**
* xmlBufFromBuffer:
* @buffer: incoming old buffer to convert to a new one
*
@@ -932,12 +871,19 @@
if (buf == NULL)
return(NULL);
CHECK_COMPAT(buf)
- if ((buf->error) || (buf->buffer == NULL)) {
+ ret = buf->buffer;
+
+ if ((buf->error) || (ret == NULL)) {
xmlBufFree(buf);
+ if (ret != NULL) {
+ ret->content = NULL;
+ ret->contentIO = NULL;
+ ret->use = 0;
+ ret->size = 0;
+ }
return(NULL);
}
- ret = buf->buffer;
/*
* What to do in case of error in the buffer ???
*/
diff --git a/src/config.h.in b/src/config.h.in
index f07ca83..9954a4a 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -21,13 +21,13 @@
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
-/* Define to 1 if you have the `ftime' function. */
+/* Define to 1 if you have the 'ftime' function. */
#undef HAVE_FTIME
-/* Define to 1 if you have the `getentropy' function. */
+/* Define to 1 if you have the 'getentropy' function. */
#undef HAVE_GETENTROPY
-/* Define to 1 if you have the `gettimeofday' function. */
+/* Define to 1 if you have the 'gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY
/* Define to 1 if you have the <glob.h> header file. */
@@ -36,7 +36,7 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
-/* Define to 1 if you have the `isascii' function. */
+/* Define to 1 if you have the 'isascii' function. */
#undef HAVE_ISASCII
/* Define if history library is there (-lhistory) */
@@ -48,10 +48,10 @@
/* Define to 1 if you have the <lzma.h> header file. */
#undef HAVE_LZMA_H
-/* Define to 1 if you have the `mmap' function. */
+/* Define to 1 if you have the 'mmap' function. */
#undef HAVE_MMAP
-/* Define to 1 if you have the `munmap' function. */
+/* Define to 1 if you have the 'munmap' function. */
#undef HAVE_MUNMAP
/* mmap() is no good without munmap() */
@@ -74,7 +74,7 @@
/* Have shl_load based dso */
#undef HAVE_SHLLOAD
-/* Define to 1 if you have the `stat' function. */
+/* Define to 1 if you have the 'stat' function. */
#undef HAVE_STAT
/* Define to 1 if you have the <stdint.h> header file. */
@@ -146,7 +146,7 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
-/* Define to 1 if all of the C90 standard headers exist (not just the ones
+/* Define to 1 if all of the C89 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#undef STDC_HEADERS
diff --git a/src/dict.c b/src/dict.c
index 7a49289..96435d5 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -23,12 +23,6 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
-#include <time.h>
-
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#endif
#include "private/dict.h"
#include "private/globals.h"
@@ -912,6 +906,16 @@
* Pseudo-random generator
*/
+#ifdef _WIN32
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+#elif defined(HAVE_GETENTROPY)
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+#endif
+#include <time.h>
+
static xmlMutex xmlRngMutex;
static unsigned globalRngState[2];
diff --git a/src/encoding.c b/src/encoding.c
index 0f58029..f1cd440 100644
--- a/src/encoding.c
+++ b/src/encoding.c
@@ -2491,7 +2491,6 @@
*/
charrefLen = snprintf((char *) &charref[0], sizeof(charref),
"&#%d;", cur);
- xmlBufShrink(in, len);
xmlBufGrow(out, charrefLen * 4);
c_out = xmlBufAvail(out);
c_in = charrefLen;
@@ -2502,6 +2501,7 @@
goto error;
}
+ xmlBufShrink(in, len);
xmlBufAddLen(out, c_out);
writtentot += c_out;
goto retry;
diff --git a/src/entities.c b/src/entities.c
index 9e951c3..c679cb3 100644
--- a/src/entities.c
+++ b/src/entities.c
@@ -253,7 +253,7 @@
}
table = dtd->pentities;
break;
- case XML_INTERNAL_PREDEFINED_ENTITY:
+ default:
return(XML_ERR_ARGUMENT);
}
ret = xmlCreateEntity(dtd->doc, name, type, ExternalID, SystemID, content);
@@ -395,6 +395,8 @@
if ((doc != NULL) && (doc->intSubset != NULL)) {
return(xmlAddDocEntity(doc, name, type, ExternalID, SystemID, content));
}
+ if (name == NULL)
+ return(NULL);
return(xmlCreateEntity(doc, name, type, ExternalID, SystemID, content));
}
@@ -654,11 +656,6 @@
l = 4;
val = xmlGetUTF8Char(cur, &l);
if (val < 0) {
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- fprintf(stderr, "xmlEncodeEntitiesInternal: "
- "invalid UTF-8\n");
- abort();
-#endif
val = 0xFFFD;
cur++;
} else {
@@ -937,7 +934,8 @@
save = xmlSaveToBuffer(buf, NULL, 0);
xmlSaveTree(save, (xmlNodePtr) ent);
- xmlSaveClose(save);
+ if (xmlSaveFinish(save) != XML_ERR_OK)
+ xmlFree(xmlBufferDetach(buf));
}
/**
@@ -948,9 +946,9 @@
* When using the hash table scan function, arguments need to be reversed
*/
static void
-xmlDumpEntityDeclScan(void *ent, void *buf,
+xmlDumpEntityDeclScan(void *ent, void *save,
const xmlChar *name ATTRIBUTE_UNUSED) {
- xmlDumpEntityDecl((xmlBufferPtr) buf, (xmlEntityPtr) ent);
+ xmlSaveTree(save, ent);
}
/**
@@ -962,6 +960,14 @@
*/
void
xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
- xmlHashScan(table, xmlDumpEntityDeclScan, buf);
+ xmlSaveCtxtPtr save;
+
+ if ((buf == NULL) || (table == NULL))
+ return;
+
+ save = xmlSaveToBuffer(buf, NULL, 0);
+ xmlHashScan(table, xmlDumpEntityDeclScan, save);
+ if (xmlSaveFinish(save) != XML_ERR_OK)
+ xmlFree(xmlBufferDetach(buf));
}
#endif /* LIBXML_OUTPUT_ENABLED */
diff --git a/src/error.c b/src/error.c
index e5553d5..f47edb6 100644
--- a/src/error.c
+++ b/src/error.c
@@ -698,8 +698,7 @@
if (code == XML_ERR_OK)
return(0);
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- if ((code == XML_ERR_INTERNAL_ERROR) ||
- (code == XML_ERR_ARGUMENT)) {
+ if (code == XML_ERR_INTERNAL_ERROR) {
fprintf(stderr, "Unexpected error: %d\n", code);
abort();
}
@@ -1307,6 +1306,8 @@
errmsg = "already in use"; break;
case XML_IO_EAFNOSUPPORT:
errmsg = "unknown address family"; break;
+ case XML_IO_UNSUPPORTED_PROTOCOL:
+ errmsg = "unsupported protocol"; break;
default:
errmsg = "Unregistered error message";
diff --git a/src/gentest.py b/src/gentest.py
index 79025f8..ebb5218 100755
--- a/src/gentest.py
+++ b/src/gentest.py
@@ -224,7 +224,7 @@
"xmlAddPrevSibling":
"if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
"xmlDocSetRootElement":
- "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
+ "if (ret_val == NULL) { xmlFreeNode(root) ; root = NULL ; }",
"xmlReplaceNode":
"""if (cur != NULL) {
xmlUnlinkNode(cur);
@@ -234,9 +234,10 @@
xmlFreeNode(old) ; old = NULL ; }
\t ret_val = NULL;""",
"xmlTextMerge":
- """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
+ """if (ret_val == NULL) {
xmlUnlinkNode(second);
- xmlFreeNode(second) ; second = NULL ; }""",
+ xmlFreeNode(second) ; second = NULL ;
+ ret_val = first; }""",
"xmlBuildQName":
"""if ((ret_val != NULL) && (ret_val != ncname) &&
(ret_val != prefix) && (ret_val != memory))
diff --git a/src/include/libxml/tree.h b/src/include/libxml/tree.h
index 03449ce..bc99548 100644
--- a/src/include/libxml/tree.h
+++ b/src/include/libxml/tree.h
@@ -164,13 +164,13 @@
XML_TEXT_NODE= 3,
XML_CDATA_SECTION_NODE= 4,
XML_ENTITY_REF_NODE= 5,
- XML_ENTITY_NODE= 6,
+ XML_ENTITY_NODE= 6, /* unused */
XML_PI_NODE= 7,
XML_COMMENT_NODE= 8,
XML_DOCUMENT_NODE= 9,
- XML_DOCUMENT_TYPE_NODE= 10,
+ XML_DOCUMENT_TYPE_NODE= 10, /* unused */
XML_DOCUMENT_FRAG_NODE= 11,
- XML_NOTATION_NODE= 12,
+ XML_NOTATION_NODE= 12, /* unused */
XML_HTML_DOCUMENT_NODE= 13,
XML_DTD_NODE= 14,
XML_ELEMENT_DECL= 15,
@@ -1003,10 +1003,10 @@
xmlFreeNodeList (xmlNodePtr cur);
XMLPUBFUN void
xmlFreeNode (xmlNodePtr cur);
-XMLPUBFUN void
+XMLPUBFUN int
xmlSetTreeDoc (xmlNodePtr tree,
xmlDocPtr doc);
-XMLPUBFUN void
+XMLPUBFUN int
xmlSetListDoc (xmlNodePtr list,
xmlDocPtr doc);
/*
@@ -1125,10 +1125,10 @@
XMLPUBFUN int
xmlNodeGetSpacePreserve (const xmlNode *cur);
#ifdef LIBXML_TREE_ENABLED
-XMLPUBFUN void
+XMLPUBFUN int
xmlNodeSetLang (xmlNodePtr cur,
const xmlChar *lang);
-XMLPUBFUN void
+XMLPUBFUN int
xmlNodeSetSpacePreserve (xmlNodePtr cur,
int val);
#endif /* LIBXML_TREE_ENABLED */
diff --git a/src/include/libxml/valid.h b/src/include/libxml/valid.h
index 10d6d19..361e965 100644
--- a/src/include/libxml/valid.h
+++ b/src/include/libxml/valid.h
@@ -255,11 +255,8 @@
/* IDs */
XMLPUBFUN int
- xmlAddIDSafe (xmlDocPtr doc,
- const xmlChar *value,
- xmlAttrPtr attr,
- int streaming,
- xmlIDPtr *id);
+ xmlAddIDSafe (xmlAttrPtr attr,
+ const xmlChar *value);
XMLPUBFUN xmlIDPtr
xmlAddID (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
@@ -312,31 +309,38 @@
XMLPUBFUN void
xmlFreeValidCtxt(xmlValidCtxtPtr);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateRoot (xmlValidCtxtPtr ctxt,
xmlDocPtr doc);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateElementDecl (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
xmlElementPtr elem);
+XML_DEPRECATED
XMLPUBFUN xmlChar *
xmlValidNormalizeAttributeValue(xmlDocPtr doc,
xmlNodePtr elem,
const xmlChar *name,
const xmlChar *value);
+XML_DEPRECATED
XMLPUBFUN xmlChar *
xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
xmlNodePtr elem,
const xmlChar *name,
const xmlChar *value);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
xmlAttributePtr attr);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateAttributeValue(xmlAttributeType type,
const xmlChar *value);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateNotationDecl (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
@@ -345,6 +349,7 @@
xmlValidateDtd (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
xmlDtdPtr dtd);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateDtdFinal (xmlValidCtxtPtr ctxt,
xmlDocPtr doc);
@@ -355,16 +360,19 @@
xmlValidateElement (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
xmlNodePtr elem);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateOneElement (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
xmlNodePtr elem);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateOneAttribute (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
xmlNodePtr elem,
xmlAttrPtr attr,
const xmlChar *value);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateOneNamespace (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
@@ -372,12 +380,14 @@
const xmlChar *prefix,
xmlNsPtr ns,
const xmlChar *value);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt,
xmlDocPtr doc);
#endif /* LIBXML_VALID_ENABLED */
#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
+XML_DEPRECATED
XMLPUBFUN int
xmlValidateNotationUse (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
@@ -433,19 +443,23 @@
/*
* Validation based on the regexp support
*/
+XML_DEPRECATED
XMLPUBFUN int
xmlValidBuildContentModel(xmlValidCtxtPtr ctxt,
xmlElementPtr elem);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidatePushElement (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
xmlNodePtr elem,
const xmlChar *qname);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidatePushCData (xmlValidCtxtPtr ctxt,
const xmlChar *data,
int len);
+XML_DEPRECATED
XMLPUBFUN int
xmlValidatePopElement (xmlValidCtxtPtr ctxt,
xmlDocPtr doc,
diff --git a/src/include/libxml/xmlerror.h b/src/include/libxml/xmlerror.h
index 373e5f6..7d83f45 100644
--- a/src/include/libxml/xmlerror.h
+++ b/src/include/libxml/xmlerror.h
@@ -478,6 +478,7 @@
XML_IO_EADDRINUSE, /* 1554 */
XML_IO_EALREADY, /* 1555 */
XML_IO_EAFNOSUPPORT, /* 1556 */
+ XML_IO_UNSUPPORTED_PROTOCOL, /* 1557 */
XML_XINCLUDE_RECURSION=1600,
XML_XINCLUDE_PARSE_VALUE, /* 1601 */
XML_XINCLUDE_ENTITY_DEF_MISMATCH, /* 1602 */
diff --git a/src/include/private/buf.h b/src/include/private/buf.h
index 678294f..982b9ee 100644
--- a/src/include/private/buf.h
+++ b/src/include/private/buf.h
@@ -28,10 +28,6 @@
xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len);
XML_HIDDEN int
xmlBufCat(xmlBufPtr buf, const xmlChar *str);
-XML_HIDDEN int
-xmlBufCCat(xmlBufPtr buf, const char *str);
-XML_HIDDEN int
-xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string);
XML_HIDDEN size_t
xmlBufAvail(const xmlBufPtr buf);
diff --git a/src/include/private/io.h b/src/include/private/io.h
index 01c2ced..a2535ae 100644
--- a/src/include/private/io.h
+++ b/src/include/private/io.h
@@ -27,6 +27,9 @@
#ifdef LIBXML_OUTPUT_ENABLED
XML_HIDDEN xmlOutputBufferPtr
xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
+XML_HIDDEN void
+xmlOutputBufferWriteQuotedString(xmlOutputBufferPtr buf,
+ const xmlChar *string);
#endif
#endif /* XML_IO_H_PRIVATE__ */
diff --git a/src/include/private/parser.h b/src/include/private/parser.h
index c5df068..d7bb782 100644
--- a/src/include/private/parser.h
+++ b/src/include/private/parser.h
@@ -68,6 +68,8 @@
xmlDetectEncoding(xmlParserCtxtPtr ctxt);
XML_HIDDEN void
xmlSetDeclaredEncoding(xmlParserCtxtPtr ctxt, xmlChar *encoding);
+XML_HIDDEN const xmlChar *
+xmlGetActualEncoding(xmlParserCtxtPtr ctxt);
XML_HIDDEN xmlParserNsData *
xmlParserNsCreate(void);
diff --git a/src/include/private/save.h b/src/include/private/save.h
index 6e16a2f..5d4a753 100644
--- a/src/include/private/save.h
+++ b/src/include/private/save.h
@@ -13,8 +13,8 @@
xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur);
XML_HIDDEN void
-xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc,
- xmlAttrPtr attr, const xmlChar * string);
+xmlBufAttrSerializeTxtContent(xmlOutputBufferPtr buf, xmlDocPtr doc,
+ const xmlChar *string);
XML_HIDDEN void
xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
diff --git a/src/include/private/tree.h b/src/include/private/tree.h
index a88cb0e..2d651d5 100644
--- a/src/include/private/tree.h
+++ b/src/include/private/tree.h
@@ -9,8 +9,13 @@
XML_HIDDEN extern int
__xmlRegisterCallbacks;
-XML_HIDDEN xmlNsPtr
-xmlTreeEnsureXMLDecl(xmlDocPtr doc);
+XML_HIDDEN int
+xmlSearchNsSafe(xmlNodePtr node, const xmlChar *href, xmlNsPtr *out);
+XML_HIDDEN int
+xmlSearchNsByHrefSafe(xmlNodePtr node, const xmlChar *href, xmlNsPtr *out);
+
+XML_HIDDEN int
+xmlNodeParseContent(xmlNodePtr node, const xmlChar *content, int len);
XML_HIDDEN xmlNodePtr
xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
int extended);
diff --git a/src/nanohttp.c b/src/nanohttp.c
index 81da585..e508292 100644
--- a/src/nanohttp.c
+++ b/src/nanohttp.c
@@ -1388,7 +1388,7 @@
}
if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
- __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI");
+ __xmlIOErr(XML_FROM_IO, XML_IO_UNSUPPORTED_PROTOCOL, ctxt->protocol);
xmlNanoHTTPFreeCtxt(ctxt);
if (redirURL != NULL) xmlFree(redirURL);
return(NULL);
diff --git a/src/parser.c b/src/parser.c
index 8859e3c..95f3ed1 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -2980,13 +2980,6 @@
if (cur == NULL) return(NULL);
-#ifndef XML_XML_NAMESPACE
- /* xml: prefix is not really a namespace */
- if ((cur[0] == 'x') && (cur[1] == 'm') &&
- (cur[2] == 'l') && (cur[3] == ':'))
- return(xmlStrdup(name));
-#endif
-
/* nasty but well=formed */
if (cur[0] == ':')
return(xmlStrdup(name));
@@ -8910,7 +8903,7 @@
int nsIndex = (int) (ptrdiff_t) atts[2];
if ((nsIndex == NS_INDEX_EMPTY) ? (uri == NULL) :
- (nsIndex == NS_INDEX_XML) ? (uri == ctxt->str_xml) :
+ (nsIndex == NS_INDEX_XML) ? (uri == ctxt->str_xml_ns) :
(uri == ctxt->nsTab[nsIndex * 2 + 1]))
return(bucket->index);
}
diff --git a/src/parserInternals.c b/src/parserInternals.c
index 4d3dc7f..fa69110 100644
--- a/src/parserInternals.c
+++ b/src/parserInternals.c
@@ -1398,6 +1398,30 @@
ctxt->encoding = encoding;
}
+/**
+ * xmlGetActualEncoding:
+ * @ctxt: the parser context
+ *
+ * Returns the actual used to parse the document. This can differ from
+ * the declared encoding.
+ */
+const xmlChar *
+xmlGetActualEncoding(xmlParserCtxtPtr ctxt) {
+ const xmlChar *encoding = NULL;
+
+ if ((ctxt->input->flags & XML_INPUT_USES_ENC_DECL) ||
+ (ctxt->input->flags & XML_INPUT_AUTO_ENCODING)) {
+ /* Preserve encoding exactly */
+ encoding = ctxt->encoding;
+ } else if ((ctxt->input->buf) && (ctxt->input->buf->encoder)) {
+ encoding = BAD_CAST ctxt->input->buf->encoder->name;
+ } else if (ctxt->input->flags & XML_INPUT_HAS_ENCODING) {
+ encoding = BAD_CAST "UTF-8";
+ }
+
+ return(encoding);
+}
+
/************************************************************************
* *
* Commodity functions to handle entities processing *
diff --git a/src/testapi.c b/src/testapi.c
index 35c74fa..bbfb2a1 100644
--- a/src/testapi.c
+++ b/src/testapi.c
@@ -19789,7 +19789,7 @@
root = gen_xmlNodePtr_in(n_root, 1);
ret_val = xmlDocSetRootElement(doc, root);
- if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }
+ if (ret_val == NULL) { xmlFreeNode(root) ; root = NULL ; }
desret_xmlNodePtr(ret_val);
call_tests++;
des_xmlDocPtr(n_doc, doc, 0);
@@ -23412,9 +23412,10 @@
second = gen_xmlNodePtr_in(n_second, 1);
ret_val = xmlTextMerge(first, second);
- if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
+ if (ret_val == NULL) {
xmlUnlinkNode(second);
- xmlFreeNode(second) ; second = NULL ; }
+ xmlFreeNode(second) ; second = NULL ;
+ ret_val = first; }
desret_xmlNodePtr(ret_val);
call_tests++;
des_xmlNodePtr_in(n_first, first, 0);
diff --git a/src/testparser.c b/src/testparser.c
index 08965b5..cabc5f4 100644
--- a/src/testparser.c
+++ b/src/testparser.c
@@ -7,6 +7,7 @@
#include <libxml/parser.h>
#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>
+#include <libxml/HTMLparser.h>
#include <string.h>
@@ -143,9 +144,72 @@
return err;
}
+
+#ifdef LIBXML_HTML_ENABLED
+static int
+testHtmlPushWithEncoding(void) {
+ htmlParserCtxtPtr ctxt;
+ htmlDocPtr doc;
+ htmlNodePtr node;
+ int err = 0;
+
+ ctxt = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL,
+ XML_CHAR_ENCODING_UTF8);
+ htmlParseChunk(ctxt, "-\xC3\xA4-", 4, 1);
+
+ doc = ctxt->myDoc;
+ if (!xmlStrEqual(doc->encoding, BAD_CAST "UTF-8")) {
+ fprintf(stderr, "testHtmlPushWithEncoding failed\n");
+ err = 1;
+ }
+
+ node = xmlDocGetRootElement(doc)->children->children->children;
+ if (!xmlStrEqual(node->content, BAD_CAST "-\xC3\xA4-")) {
+ fprintf(stderr, "testHtmlPushWithEncoding failed\n");
+ err = 1;
+ }
+
+ xmlFreeDoc(doc);
+ htmlFreeParserCtxt(ctxt);
+ return err;
+}
+#endif
#endif
-#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_XINCLUDE_ENABLED)
+#ifdef LIBXML_READER_ENABLED
+static int
+testReaderEncoding(void) {
+ xmlBuffer *buf;
+ xmlTextReader *reader;
+ xmlChar *xml;
+ const xmlChar *encoding;
+ int err = 0;
+ int i;
+
+ buf = xmlBufferCreate();
+ xmlBufferCCat(buf, "<?xml version='1.0' encoding='ISO-8859-1'?>\n");
+ xmlBufferCCat(buf, "<doc>");
+ for (i = 0; i < 8192; i++)
+ xmlBufferCCat(buf, "x");
+ xmlBufferCCat(buf, "</doc>");
+ xml = xmlBufferDetach(buf);
+ xmlBufferFree(buf);
+
+ reader = xmlReaderForDoc(BAD_CAST xml, NULL, NULL, 0);
+ xmlTextReaderRead(reader);
+ encoding = xmlTextReaderConstEncoding(reader);
+
+ if (!xmlStrEqual(encoding, BAD_CAST "ISO-8859-1")) {
+ fprintf(stderr, "testReaderEncoding failed\n");
+ err = 1;
+ }
+
+ xmlFreeTextReader(reader);
+ xmlFree(xml);
+ return err;
+}
+
+#ifdef LIBXML_XINCLUDE_ENABLED
typedef struct {
char *message;
int code;
@@ -223,6 +287,7 @@
return err;
}
#endif
+#endif
#ifdef LIBXML_WRITER_ENABLED
static int
@@ -279,10 +344,16 @@
#ifdef LIBXML_PUSH_ENABLED
err |= testHugePush();
err |= testHugeEncodedChunk();
+#ifdef LIBXML_HTML_ENABLED
+ err |= testHtmlPushWithEncoding();
#endif
-#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_XINCLUDE_ENABLED)
+#endif
+#ifdef LIBXML_READER_ENABLED
+ err |= testReaderEncoding();
+#ifdef LIBXML_XINCLUDE_ENABLED
err |= testReaderXIncludeError();
#endif
+#endif
#ifdef LIBXML_WRITER_ENABLED
err |= testWriterClose();
#endif
diff --git a/src/tree.c b/src/tree.c
index f9cab14..a8869fd 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -56,10 +56,17 @@
************************************************************************/
static xmlNsPtr
-xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
+xmlNewReconciledNs(xmlNodePtr tree, xmlNsPtr ns);
+
+static xmlAttrPtr
+xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name,
+ const xmlChar *nsName, int useDTD);
static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
+static void
+xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree);
+
/************************************************************************
* *
* A few static variables and macros *
@@ -75,19 +82,6 @@
static int xmlCompressMode = 0;
-#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; \
-}}
-
#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
(str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
@@ -218,13 +212,6 @@
*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);
@@ -292,6 +279,18 @@
return(&name[l+1]);
}
+/**
+ * xmlSplitQName4:
+ * @name: the full QName
+ * @prefixPtr: pointer to resulting prefix
+ *
+ * Parse a QName. The return value points to the start of the local
+ * name in the input string. If the QName has a prefix, it will be
+ * allocated and stored in @prefixPtr. This string must be freed by
+ * the caller. If there's no prefix, @prefixPtr is set to NULL.
+ *
+ * Returns the local name or NULL if a memory allocation failed.
+ */
const xmlChar *
xmlSplitQName4(const xmlChar *name, xmlChar **prefixPtr) {
xmlChar *prefix;
@@ -691,19 +690,21 @@
/**
* xmlNewNs:
- * @node: the element carrying the namespace
+ * @node: the element carrying the namespace (optional)
* @href: the URI associated
- * @prefix: the prefix for the namespace
+ * @prefix: the prefix for the namespace (optional)
*
- * 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.
+ * Create a new namespace. For a default namespace, @prefix should be
+ * NULL. The namespace URI in @href is not checked. You should make sure
+ * to pass a valid URI.
*
- * We use href==NULL in the case of an element creation where the namespace
- * was not defined.
+ * If @node is provided, it must be an element node. The namespace will
+ * be appended to the node's namespace declarations. It is an error if
+ * the node already has a definition for the prefix or default
+ * namespace.
*
- * Returns a new namespace pointer or NULL
+ * Returns a new namespace pointer or NULL if arguments are invalid,
+ * the prefix is already in use or a memory allocation failed.
*/
xmlNsPtr
xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
@@ -742,13 +743,11 @@
} else {
xmlNsPtr prev = node->nsDef;
- if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
- (xmlStrEqual(prev->prefix, cur->prefix)))
+ if (xmlStrEqual(prev->prefix, cur->prefix))
goto error;
while (prev->next != NULL) {
prev = prev->next;
- if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
- (xmlStrEqual(prev->prefix, cur->prefix)))
+ if (xmlStrEqual(prev->prefix, cur->prefix))
goto error;
}
prev->next = cur;
@@ -764,9 +763,10 @@
/**
* xmlSetNs:
* @node: a node in the document
- * @ns: a namespace pointer
+ * @ns: a namespace pointer (optional)
*
- * Associate a namespace to a node, a posteriori.
+ * Set the namespace of an element or attribute node. Passing a NULL
+ * namespace unsets the namespace.
*/
void
xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
@@ -782,7 +782,7 @@
* xmlFreeNs:
* @cur: the namespace pointer
*
- * Free up the structures associated to a namespace
+ * Free an xmlNs object.
*/
void
xmlFreeNs(xmlNsPtr cur) {
@@ -798,7 +798,7 @@
* xmlFreeNsList:
* @cur: the first namespace pointer
*
- * Free up all the structures associated to the chained namespaces.
+ * Free a list of xmlNs objects.
*/
void
xmlFreeNsList(xmlNsPtr cur) {
@@ -815,15 +815,21 @@
/**
* xmlNewDtd:
- * @doc: the document pointer
- * @name: the DTD name
- * @ExternalID: the external ID
- * @SystemID: the system ID
+ * @doc: the document pointer (optional)
+ * @name: the DTD name (optional)
+ * @ExternalID: the external ID (optional)
+ * @SystemID: the system ID (optional)
*
- * Creation of a new DTD for the external subset. To create an
- * internal subset, use xmlCreateIntSubset().
+ * Create a DTD node.
*
- * Returns a pointer to the new DTD structure
+ * If a document is provided, it is an error if it already has an
+ * external subset. If the document has no external subset, it
+ * will be set to the created DTD.
+ *
+ * To create an internal subset, use xmlCreateIntSubset().
+ *
+ * Returns a pointer to the new DTD object or NULL if arguments are
+ * invalid or a memory allocation failed.
*/
xmlDtdPtr
xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
@@ -875,10 +881,10 @@
* xmlGetIntSubset:
* @doc: the document pointer
*
- * Get the internal subset of a document
- * Returns a pointer to the DTD structure or NULL if not found
+ * Get the internal subset of a document.
+ *
+ * Returns a pointer to the DTD object or NULL if not found.
*/
-
xmlDtdPtr
xmlGetIntSubset(const xmlDoc *doc) {
xmlNodePtr cur;
@@ -896,13 +902,20 @@
/**
* xmlCreateIntSubset:
- * @doc: the document pointer
- * @name: the DTD name
- * @ExternalID: the external (PUBLIC) ID
- * @SystemID: the system ID
+ * @doc: the document pointer (optional)
+ * @name: the DTD name (optional)
+ * @ExternalID: the external (PUBLIC) ID (optional)
+ * @SystemID: the system ID (optional)
*
- * Create the internal subset of a document
- * Returns a pointer to the new DTD structure
+ * Create a DTD node.
+ *
+ * If a document is provided and it already has an internal subset,
+ * the existing DTD object is returned without creating a new object.
+ * If the document has no internal subset, it will be set to the
+ * created DTD.
+ *
+ * Returns a pointer to the new or existing DTD object or NULL if
+ * arguments are invalid or a memory allocation failed.
*/
xmlDtdPtr
xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
@@ -999,42 +1012,6 @@
(xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
xmlFree((char *)(str));
-
-/**
- * DICT_COPY:
- * @str: a string
- *
- * Copy a string using a "dict" dictionary in the current scope,
- * if available.
- */
-#define DICT_COPY(str, cpy) \
- if (str) { \
- if (dict) { \
- if (xmlDictOwns(dict, (const xmlChar *)(str))) \
- cpy = (xmlChar *) (str); \
- else \
- cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
- } else \
- cpy = xmlStrdup((const xmlChar *)(str)); }
-
-/**
- * DICT_CONST_COPY:
- * @str: a string
- *
- * Copy a string using a "dict" dictionary in the current scope,
- * if available.
- */
-#define DICT_CONST_COPY(str, cpy) \
- if (str) { \
- if (dict) { \
- if (xmlDictOwns(dict, (const xmlChar *)(str))) \
- cpy = (const xmlChar *) (str); \
- else \
- cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
- } else \
- cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
-
-
/**
* xmlFreeDtd:
* @cur: the DTD structure to free up
@@ -1062,8 +1039,7 @@
*/
while (c != NULL) {
next = c->next;
- if ((c->type != XML_NOTATION_NODE) &&
- (c->type != XML_ELEMENT_DECL) &&
+ if ((c->type != XML_ELEMENT_DECL) &&
(c->type != XML_ATTRIBUTE_DECL) &&
(c->type != XML_ENTITY_DECL)) {
xmlUnlinkNode(c);
@@ -1093,11 +1069,11 @@
/**
* xmlNewDoc:
- * @version: xmlChar string giving the version of XML "1.0"
+ * @version: XML version string like "1.0" (optional)
*
- * Creates a new XML document
+ * Creates a new XML document. If version is NULL, "1.0" is used.
*
- * Returns a new document
+ * Returns a new document or NULL if a memory allocation failed.
*/
xmlDocPtr
xmlNewDoc(const xmlChar *version) {
@@ -1141,7 +1117,7 @@
* xmlFreeDoc:
* @cur: pointer to the document
*
- * Free up all the structures used by a document, tree included.
+ * Free a document including all children and associated DTDs.
*/
void
xmlFreeDoc(xmlDocPtr cur) {
@@ -1191,48 +1167,52 @@
}
/**
- * xmlStringLenGetNodeList:
- * @doc: the document
- * @value: the value of the text
- * @len: the length of the string value
+ * xmlNodeParseContentInternal:
+ * @doc: a document (optional)
+ * @parent: an element or attribute (optional)
+ * @value: an attribute value
+ * @len: maximum length of the attribute value
+ * @listPtr: pointer to the resulting node list (optional)
*
- * Parse the value string and build the node list associated. Should
- * produce a flat tree with only TEXTs and ENTITY_REFs.
- * Returns a pointer to the first child
+ * See xmlNodeParseContent.
+ *
+ * Returns 0 on success, -1 if a memory allocation failed.
*/
-xmlNodePtr
-xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) {
- xmlNodePtr ret = NULL, head = NULL, last = NULL;
+static int
+xmlNodeParseContentInternal(const xmlDoc *doc, xmlNodePtr parent,
+ const xmlChar *value, int len,
+ xmlNodePtr *listPtr) {
+ xmlNodePtr head = NULL, last = NULL;
xmlNodePtr node;
xmlChar *val = NULL;
- const xmlChar *cur, *end;
+ const xmlChar *cur;
const xmlChar *q;
xmlEntityPtr ent;
xmlBufPtr buf;
+ int remaining;
- /*
- * This function should only receive valid attribute values that
- * were checked by the parser, typically by xmlParseAttValueComplex
- * calling xmlStringDecodeEntities.
- *
- * In recovery mode, the parser can produce invalid attribute
- * values. For now, we ignore any errors silently. If this is fixed,
- * we could add assertions here to catch parser issues.
- */
+ if (listPtr != NULL)
+ *listPtr = NULL;
- if (value == NULL) return(NULL);
+ if (len < 0)
+ remaining = INT_MAX;
+ else
+ remaining = len;
+
+ if (value == NULL)
+ goto done;
+
cur = value;
- end = cur + len;
- buf = xmlBufCreateSize(0);
- if (buf == NULL) return(NULL);
+ buf = xmlBufCreateSize(64);
+ if (buf == NULL)
+ return(-1);
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
q = cur;
- while ((cur < end) && (*cur != 0)) {
+ while ((remaining > 0) && (*cur != 0)) {
if (cur[0] == '&') {
int charval = 0;
- xmlChar tmp;
/*
* Save the current text.
@@ -1240,15 +1220,15 @@
if (cur != q) {
if (xmlBufAdd(buf, q, cur - q))
goto out;
+ q = cur;
}
- q = cur;
- if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
+
+ if ((remaining > 2) && (cur[1] == '#') && (cur[2] == 'x')) {
+ int tmp = 0;
+
cur += 3;
- if (cur < end)
- tmp = *cur;
- else
- tmp = 0;
- while (tmp != ';') { /* Non input consuming loop */
+ remaining -= 3;
+ while ((remaining > 0) && ((tmp = *cur) != ';')) {
if ((tmp >= '0') && (tmp <= '9'))
charval = charval * 16 + (tmp - '0');
else if ((tmp >= 'a') && (tmp <= 'f'))
@@ -1259,56 +1239,61 @@
charval = 0;
break;
}
+ if (charval > 0x110000)
+ charval = 0x110000;
cur++;
- if (cur < end)
- tmp = *cur;
- else
- tmp = 0;
+ remaining--;
}
- if (tmp == ';')
+ if (tmp == ';') {
cur++;
+ remaining--;
+ }
q = cur;
- } else if ((cur + 1 < end) && (cur[1] == '#')) {
+ } else if ((remaining > 1) && (cur[1] == '#')) {
+ int tmp = 0;
+
cur += 2;
- if (cur < end)
- tmp = *cur;
- else
- tmp = 0;
- while (tmp != ';') { /* Non input consuming loops */
- /* Don't check for integer overflow, see above. */
+ remaining -= 2;
+ while ((remaining > 0) && ((tmp = *cur) != ';')) {
if ((tmp >= '0') && (tmp <= '9'))
charval = charval * 10 + (tmp - '0');
else {
charval = 0;
break;
}
+ if (charval > 0x110000)
+ charval = 0x110000;
cur++;
- if (cur < end)
- tmp = *cur;
- else
- tmp = 0;
+ remaining--;
}
- if (tmp == ';')
+ if (tmp == ';') {
cur++;
+ remaining--;
+ }
q = cur;
} else {
/*
* Read the entity string
*/
cur++;
+ remaining--;
q = cur;
- while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
- if ((cur >= end) || (*cur == 0))
+ while ((remaining > 0) && (*cur != 0) && (*cur != ';')) {
+ cur++;
+ remaining--;
+ }
+ if ((remaining <= 0) || (*cur == 0))
break;
if (cur != q) {
- /*
- * Predefined entities don't generate nodes
- */
val = xmlStrndup(q, cur - q);
+ if (val == NULL)
+ goto out;
ent = xmlGetDocEntity(doc, val);
if ((ent != NULL) &&
(ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
-
+ /*
+ * Predefined entities don't generate nodes
+ */
if (xmlBufCat(buf, ent->content))
goto out;
} else {
@@ -1320,72 +1305,77 @@
if (node == NULL)
goto out;
node->content = xmlBufDetach(buf);
+ node->parent = parent;
if (last == NULL) {
- last = head = node;
+ head = node;
} else {
- last = xmlAddNextSibling(last, node);
+ last->next = node;
+ node->prev = last;
}
+ last = node;
+ }
+
+ if ((ent != NULL) &&
+ ((ent->flags & XML_ENT_PARSED) == 0) &&
+ ((ent->flags & XML_ENT_EXPANDING) == 0) &&
+ (ent->content != NULL)) {
+ int res;
+
+ ent->flags |= XML_ENT_EXPANDING;
+ res = xmlNodeParseContentInternal(doc,
+ (xmlNodePtr) ent, ent->content, -1, NULL);
+ ent->flags &= ~XML_ENT_EXPANDING;
+ if (res < 0)
+ goto out;
+ ent->flags |= XML_ENT_PARSED;
}
/*
* Create a new REFERENCE_REF node
*/
- node = xmlNewReference(doc, val);
+ node = xmlNewCharRef((xmlDocPtr) doc, val);
if (node == NULL)
goto out;
- else if ((ent != NULL) &&
- ((ent->flags & XML_ENT_PARSED) == 0) &&
- ((ent->flags & XML_ENT_EXPANDING) == 0)) {
- xmlNodePtr temp;
+ node->parent = parent;
+ node->last = (xmlNodePtr) ent;
+ if (ent != NULL) {
+ node->children = (xmlNodePtr) ent;
+ node->content = ent->content;
+ }
- /*
- * The entity should have been checked already,
- * but set the flag anyway to avoid recursion.
- */
- if (node->content != NULL) {
- ent->flags |= XML_ENT_EXPANDING;
- ent->children = xmlStringGetNodeList(doc,
- node->content);
- ent->flags &= ~XML_ENT_EXPANDING;
- if (ent->children == NULL) {
- xmlFreeNode(node);
- goto out;
- }
- }
- ent->flags |= XML_ENT_PARSED;
- temp = ent->children;
- while (temp) {
- temp->parent = (xmlNodePtr)ent;
- ent->last = temp;
- temp = temp->next;
- }
- }
if (last == NULL) {
- last = head = node;
+ head = node;
} else {
- last = xmlAddNextSibling(last, node);
+ last->next = node;
+ node->prev = last;
}
+ last = node;
}
xmlFree(val);
val = NULL;
}
cur++;
+ remaining--;
q = cur;
}
if (charval != 0) {
xmlChar buffer[10];
int l;
+ if (charval >= 0x110000)
+ charval = 0xFFFD; /* replacement character */
+
l = xmlCopyCharMultiByte(buffer, charval);
buffer[l] = 0;
if (xmlBufCat(buf, buffer))
goto out;
- charval = 0;
}
- } else
+ } else {
cur++;
+ remaining--;
+ }
}
if (cur != q) {
@@ -1400,19 +1390,38 @@
node = xmlNewDocText(doc, NULL);
if (node == NULL)
goto out;
+ node->parent = parent;
node->content = xmlBufDetach(buf);
if (last == NULL) {
head = node;
} else {
- xmlAddNextSibling(last, node);
+ last->next = node;
+ node->prev = last;
}
+ last = node;
} else if (head == NULL) {
head = xmlNewDocText(doc, BAD_CAST "");
+ if (head == NULL)
+ goto out;
+ head->parent = parent;
+ last = head;
}
- ret = head;
- head = NULL;
+ xmlBufFree(buf);
+
+done:
+ if (parent != NULL) {
+ if (parent->children != NULL)
+ xmlFreeNodeList(parent->children);
+ parent->children = head;
+ parent->last = last;
+ }
+
+ if (listPtr != NULL)
+ *listPtr = head;
+
+ return(0);
out:
xmlBufFree(buf);
@@ -1420,405 +1429,209 @@
xmlFree(val);
if (head != NULL)
xmlFreeNodeList(head);
+ return(-1);
+}
+
+/**
+ * xmlNodeParseContent:
+ * @node: an element or attribute
+ * @content: text content with XML references
+ * @len: maximum length of content
+ *
+ * Parse content and replace the node's children with the resulting
+ * node list.
+ *
+ * @content is expected to be a valid XML attribute value possibly
+ * containing character and entity references. Syntax errors
+ * and references to undeclared entities are ignored silently.
+ * Only references are handled, nested elements, comments or PIs are
+ * not.
+ *
+ * Returns 0 on success, -1 if a memory allocation failed.
+ */
+int
+xmlNodeParseContent(xmlNodePtr node, const xmlChar *content, int len) {
+ return(xmlNodeParseContentInternal(node->doc, node, content, len, NULL));
+}
+
+/**
+ * xmlStringLenGetNodeList:
+ * @doc: a document (optional)
+ * @value: an attribute value
+ * @len: maximum length of the attribute value
+ *
+ * DEPRECATED: Use xmlNodeSetContentLen.
+ *
+ * See xmlStringGetNodeList.
+ *
+ * Returns a pointer to the first child or NULL if a memory
+ * allocation failed.
+ */
+xmlNodePtr
+xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) {
+ xmlNodePtr ret;
+
+ xmlNodeParseContentInternal(doc, NULL, value, len, &ret);
return(ret);
}
/**
* xmlStringGetNodeList:
- * @doc: the document
- * @value: the value of the attribute
+ * @doc: a document (optional)
+ * @value: an attribute value
*
- * Parse the value string and build the node list associated. Should
- * produce a flat tree with only TEXTs and ENTITY_REFs.
- * Returns a pointer to the first child
+ * DEPRECATED: Use xmlNodeSetContent.
+ *
+ * Parse an attribute value and build a node list containing only
+ * text and entity reference nodes. The resulting nodes will be
+ * associated with the document if provided. The document is also
+ * used to look up entities.
+ *
+ * The input is not validated. Syntax errors or references to
+ * undeclared entities will be ignored silently with unspecified
+ * results.
+ *
+ * Returns a pointer to the first child or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr
xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) {
- xmlNodePtr ret = NULL, head = NULL, last = NULL;
- xmlNodePtr node;
- xmlChar *val = NULL;
- const xmlChar *cur = value;
- const xmlChar *q;
- xmlEntityPtr ent;
- xmlBufPtr buf;
+ xmlNodePtr ret;
- /*
- * This function should only receive valid attribute values that
- * were checked by the parser, typically by xmlParseAttValueComplex
- * calling xmlStringDecodeEntities.
- *
- * In recovery mode, the parser can produce invalid attribute
- * values. For now, we ignore any errors silently. If this is fixed,
- * we could add assertions here to catch parser issues.
- */
-
- if (value == NULL) return(NULL);
-
- buf = xmlBufCreateSize(0);
- if (buf == NULL) return(NULL);
- xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
-
- q = cur;
- while (*cur != 0) {
- if (cur[0] == '&') {
- int charval = 0;
- xmlChar tmp;
-
- /*
- * Save the current text.
- */
- if (cur != q) {
- if (xmlBufAdd(buf, q, cur - q))
- goto out;
- }
- q = cur;
- if ((cur[1] == '#') && (cur[2] == 'x')) {
- cur += 3;
- tmp = *cur;
- while (tmp != ';') { /* Non input consuming loop */
- if ((tmp >= '0') && (tmp <= '9'))
- charval = charval * 16 + (tmp - '0');
- else if ((tmp >= 'a') && (tmp <= 'f'))
- charval = charval * 16 + (tmp - 'a') + 10;
- else if ((tmp >= 'A') && (tmp <= 'F'))
- charval = charval * 16 + (tmp - 'A') + 10;
- else {
- charval = 0;
- break;
- }
- cur++;
- tmp = *cur;
- }
- if (tmp == ';')
- cur++;
- q = cur;
- } else if (cur[1] == '#') {
- cur += 2;
- tmp = *cur;
- while (tmp != ';') { /* Non input consuming loops */
- /* Don't check for integer overflow, see above. */
- if ((tmp >= '0') && (tmp <= '9'))
- charval = charval * 10 + (tmp - '0');
- else {
- charval = 0;
- break;
- }
- cur++;
- tmp = *cur;
- }
- if (tmp == ';')
- cur++;
- q = cur;
- } else {
- /*
- * Read the entity string
- */
- cur++;
- q = cur;
- while ((*cur != 0) && (*cur != ';')) cur++;
- if (*cur == 0)
- break;
- if (cur != q) {
- /*
- * Predefined entities don't generate nodes
- */
- val = xmlStrndup(q, cur - q);
- if (val == NULL)
- goto out;
- ent = xmlGetDocEntity(doc, val);
- if ((ent != NULL) &&
- (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
-
- if (xmlBufCat(buf, ent->content))
- goto out;
-
- } else {
- /*
- * Flush buffer so far
- */
- if (!xmlBufIsEmpty(buf)) {
- node = xmlNewDocText(doc, NULL);
- if (node == NULL)
- goto out;
- node->content = xmlBufDetach(buf);
-
- if (last == NULL) {
- last = head = node;
- } else {
- last = xmlAddNextSibling(last, node);
- }
- }
-
- /*
- * Create a new REFERENCE_REF node
- */
- node = xmlNewReference(doc, val);
- if (node == NULL)
- goto out;
- if ((ent != NULL) &&
- ((ent->flags & XML_ENT_PARSED) == 0) &&
- ((ent->flags & XML_ENT_EXPANDING) == 0)) {
- xmlNodePtr temp;
-
- /*
- * The entity should have been checked already,
- * but set the flag anyway to avoid recursion.
- */
- if (node->content != NULL) {
- ent->flags |= XML_ENT_EXPANDING;
- ent->children = xmlStringGetNodeList(doc,
- node->content);
- ent->flags &= ~XML_ENT_EXPANDING;
- if (ent->children == NULL) {
- xmlFreeNode(node);
- goto out;
- }
- }
- ent->flags |= XML_ENT_PARSED;
- temp = ent->children;
- while (temp) {
- temp->parent = (xmlNodePtr)ent;
- ent->last = temp;
- temp = temp->next;
- }
- }
- if (last == NULL) {
- last = head = node;
- } else {
- last = xmlAddNextSibling(last, node);
- }
- }
- xmlFree(val);
- val = NULL;
- }
- cur++;
- q = cur;
- }
- if (charval != 0) {
- xmlChar buffer[10];
- int len;
-
- len = xmlCopyCharMultiByte(buffer, charval);
- buffer[len] = 0;
-
- if (xmlBufCat(buf, buffer))
- goto out;
- charval = 0;
- }
- } else
- cur++;
- }
- if ((cur != q) || (head == NULL)) {
- /*
- * Handle the last piece of text.
- */
- xmlBufAdd(buf, q, cur - q);
- }
-
- if (xmlBufIsEmpty(buf) <= 0) {
- node = xmlNewDocText(doc, NULL);
- if (node == NULL)
- goto out;
- node->content = xmlBufDetach(buf);
- if (node->content == NULL) {
- xmlFreeNode(node);
- goto out;
- }
-
- if (last == NULL) {
- head = node;
- } else {
- xmlAddNextSibling(last, node);
- }
- } else if (head == NULL) {
- head = xmlNewDocText(doc, BAD_CAST "");
- }
-
- ret = head;
- head = NULL;
-
-out:
- xmlBufFree(buf);
- if (val != NULL) xmlFree(val);
- if (head != NULL) xmlFreeNodeList(head);
+ xmlNodeParseContentInternal(doc, NULL, value, -1, &ret);
return(ret);
}
/**
- * xmlNodeListGetString:
- * @doc: the document
- * @list: a Node list
- * @inLine: should we replace entity contents or show their external form
+ * xmlNodeListGetStringInternal:
+ * @doc: a document (optional)
+ * @node: a node list
+ * @escMode: escape mode (0 = no, 1 = elem, 2 = attr, 3 = raw)
*
- * Build the string equivalent to the text contained in the Node list
- * made of TEXTs and ENTITY_REFs
- *
- * Returns a pointer to the string copy, the caller must free it with xmlFree().
+ * Returns a pointer to the string.
*/
-xmlChar *
-xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine)
-{
- const xmlNode *node = list;
- xmlChar *ret = NULL;
- xmlEntityPtr ent;
- int attr;
+static xmlChar *
+xmlNodeListGetStringInternal(xmlDocPtr doc, const xmlNode *node, int escMode) {
+ xmlBufPtr buf;
+ xmlChar *ret;
- if (list == NULL)
- return xmlStrdup(BAD_CAST "");
- if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE))
- attr = 1;
- else
- attr = 0;
+ if (node == NULL)
+ return(xmlStrdup(BAD_CAST ""));
+
+ if ((escMode == 0) &&
+ ((node->type == XML_TEXT_NODE) ||
+ (node->type == XML_CDATA_SECTION_NODE)) &&
+ (node->next == NULL)) {
+ if (node->content == NULL)
+ return(xmlStrdup(BAD_CAST ""));
+ return(xmlStrdup(node->content));
+ }
+
+ buf = xmlBufCreateSize(64);
+ if (buf == NULL)
+ return(NULL);
while (node != NULL) {
if ((node->type == XML_TEXT_NODE) ||
(node->type == XML_CDATA_SECTION_NODE)) {
- if (inLine) {
- ret = xmlStrcat(ret, node->content);
- if (ret == NULL)
- goto error;
- } else {
- xmlChar *buffer;
+ if (node->content != NULL) {
+ if (escMode == 0) {
+ xmlBufCat(buf, node->content);
+ } else {
+ xmlChar *encoded;
- if (attr)
- buffer = xmlEncodeAttributeEntities(doc, node->content);
- else
- buffer = xmlEncodeEntitiesReentrant(doc, node->content);
- if (buffer == NULL)
- goto error;
- ret = xmlStrcat(ret, buffer);
- xmlFree(buffer);
- if (ret == NULL)
- goto error;
+ if (escMode == 1)
+ encoded = xmlEncodeEntitiesReentrant(doc,
+ node->content);
+ else if (escMode == 2)
+ encoded = xmlEncodeAttributeEntities(doc,
+ node->content);
+ else
+ encoded = xmlEncodeSpecialChars(doc, node->content);
+ if (encoded == NULL)
+ goto error;
+ xmlBufCat(buf, encoded);
+ xmlFree(encoded);
+ }
}
} else if (node->type == XML_ENTITY_REF_NODE) {
- if (inLine) {
- ent = xmlGetDocEntity(doc, node->name);
- if (ent != NULL) {
- if (ent->children != NULL) {
- xmlChar *buffer;
-
- /* an entity content can be any "well balanced chunk",
- * i.e. the result of the content [43] production:
- * http://www.w3.org/TR/REC-xml#NT-content.
- * So it can contain text, CDATA section or nested
- * entity reference nodes (among others).
- * -> we recursive call xmlNodeListGetString()
- * which handles these types */
- buffer = xmlNodeListGetString(doc, ent->children, 1);
- if (buffer == NULL)
- goto error;
- ret = xmlStrcat(ret, buffer);
- xmlFree(buffer);
- if (ret == NULL)
- goto error;
- }
- } else if (node->content != NULL) {
- ret = xmlStrcat(ret, node->content);
- if (ret == NULL)
- goto error;
- }
+ if (escMode == 0) {
+ xmlBufGetNodeContent(buf, node);
} else {
- xmlChar buf[2];
-
- buf[0] = '&';
- buf[1] = 0;
- ret = xmlStrncat(ret, buf, 1);
- ret = xmlStrcat(ret, node->name);
- buf[0] = ';';
- buf[1] = 0;
- ret = xmlStrncat(ret, buf, 1);
- if (ret == NULL)
- goto error;
+ xmlBufAdd(buf, BAD_CAST "&", 1);
+ xmlBufCat(buf, node->name);
+ xmlBufAdd(buf, BAD_CAST ";", 1);
}
}
+
node = node->next;
}
- if (ret == NULL)
- ret = xmlStrdup(BAD_CAST "");
- return (ret);
+
+ ret = xmlBufDetach(buf);
+ xmlBufFree(buf);
+ return(ret);
error:
- xmlFree(ret);
+ xmlBufFree(buf);
return(NULL);
}
+/**
+ * xmlNodeListGetString:
+ * @doc: a document (optional)
+ * @list: a node list of attribute children (optional)
+ * @inLine: whether entity references are substituted
+ *
+ * Serializes attribute children (text and entity reference nodes)
+ * into a string. An empty list produces an empty string.
+ *
+ * If @inLine is true, entity references will be substituted.
+ * Otherwise, entity references will be kept and special characters
+ * like '&' as well as non-ASCII chars will be escaped. See
+ * xmlNodeListGetRawString for an alternative option.
+ *
+ * Returns a string or NULL if a memory allocation failed.
+ */
+xmlChar *
+xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine)
+{
+ int escMode;
+
+ if (inLine) {
+ escMode = 0;
+ } else {
+ if ((list != NULL) &&
+ (list->parent != NULL) &&
+ (list->parent->type == XML_ATTRIBUTE_NODE))
+ escMode = 2;
+ else
+ escMode = 1;
+ }
+
+ return(xmlNodeListGetStringInternal(doc, list, escMode));
+}
+
#ifdef LIBXML_TREE_ENABLED
/**
* xmlNodeListGetRawString:
- * @doc: the document
- * @list: a Node list
- * @inLine: should we replace entity contents or show their external form
+ * @doc: a document (optional)
+ * @list: a node list of attribute children (optional)
+ * @inLine: whether entity references are substituted
*
- * Builds the string equivalent to the text contained in the Node list
- * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
- * this function doesn't do any character encoding handling.
+ * Serializes attribute children (text and entity reference nodes)
+ * into a string. An empty list produces an empty string.
*
- * Returns a pointer to the string copy, the caller must free it with xmlFree().
+ * If @inLine is true, entity references will be substituted.
+ * Otherwise, entity references will be kept and special characters
+ * like '&' will be escaped.
+ *
+ * Returns a string or NULL if a memory allocation failed.
*/
xmlChar *
xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine)
{
- const xmlNode *node = list;
- xmlChar *ret = NULL;
- xmlEntityPtr ent;
-
- if (list == NULL)
- return xmlStrdup(BAD_CAST "");
-
- while (node != NULL) {
- if ((node->type == XML_TEXT_NODE) ||
- (node->type == XML_CDATA_SECTION_NODE)) {
- if (inLine) {
- ret = xmlStrcat(ret, node->content);
- } else {
- xmlChar *buffer;
-
- buffer = xmlEncodeSpecialChars(doc, node->content);
- if (buffer != NULL) {
- ret = xmlStrcat(ret, buffer);
- xmlFree(buffer);
- }
- }
- } else if (node->type == XML_ENTITY_REF_NODE) {
- if (inLine) {
- ent = xmlGetDocEntity(doc, node->name);
- if (ent != NULL) {
- xmlChar *buffer;
-
- /* an entity content can be any "well balanced chunk",
- * i.e. the result of the content [43] production:
- * http://www.w3.org/TR/REC-xml#NT-content.
- * So it can contain text, CDATA section or nested
- * entity reference nodes (among others).
- * -> we recursive call xmlNodeListGetRawString()
- * which handles these types */
- buffer =
- xmlNodeListGetRawString(doc, ent->children, 1);
- if (buffer != NULL) {
- ret = xmlStrcat(ret, buffer);
- xmlFree(buffer);
- }
- } else {
- ret = xmlStrcat(ret, node->content);
- }
- } else {
- xmlChar buf[2];
-
- buf[0] = '&';
- buf[1] = 0;
- ret = xmlStrncat(ret, buf, 1);
- ret = xmlStrcat(ret, node->name);
- buf[0] = ';';
- buf[1] = 0;
- ret = xmlStrncat(ret, buf, 1);
- }
- }
- node = node->next;
- }
- if (ret == NULL)
- ret = xmlStrdup(BAD_CAST "");
- return (ret);
+ int escMode = inLine ? 0 : 3;
+ return(xmlNodeListGetStringInternal((xmlDocPtr) doc, list, escMode));
}
#endif /* LIBXML_TREE_ENABLED */
@@ -1884,12 +1697,16 @@
cur->last = tmp;
tmp = tmp->next;
}
- }
- if ((value != NULL) && (node != NULL) &&
- (xmlIsID(node->doc, node, cur) == 1) &&
- (xmlAddIDSafe(node->doc, value, cur, 0, NULL) < 0))
- goto error;
+ if (doc != NULL) {
+ int res = xmlIsID(doc, node, cur);
+
+ if (res < 0)
+ goto error;
+ if ((res == 1) && (xmlAddIDSafe(cur, value) < 0))
+ goto error;
+ }
+ }
/*
* Add it at the end to preserve parsing order ...
@@ -1920,12 +1737,20 @@
defined(LIBXML_SCHEMAS_ENABLED)
/**
* xmlNewProp:
- * @node: the holding node
+ * @node: the parent node (optional)
* @name: the name of the attribute
- * @value: the value of the attribute
+ * @value: the value of the attribute (optional)
*
- * Create a new property carried by a node.
- * Returns a pointer to the attribute
+ * Create an attribute node.
+ *
+ * If provided, @value should be a raw, unescaped string.
+ *
+ * If @node is provided, the created attribute will be appended without
+ * checking for duplicate names. It is an error if @node is not an
+ * element.
+ *
+ * Returns a pointer to the attribute or NULL if arguments are invalid
+ * or a memory allocation failed.
*/
xmlAttrPtr
xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
@@ -1940,13 +1765,21 @@
/**
* xmlNewNsProp:
- * @node: the holding node
- * @ns: the namespace
- * @name: the name of the attribute
- * @value: the value of the attribute
+ * @node: the parent node (optional)
+ * @ns: the namespace (optional)
+ * @name: the local name of the attribute
+ * @value: the value of the attribute (optional)
*
- * Create a new property tagged with a namespace and carried by a node.
- * Returns a pointer to the attribute
+ * Create an attribute object.
+ *
+ * If provided, @value should be a raw, unescaped string.
+ *
+ * If @node is provided, the created attribute will be appended without
+ * checking for duplicate names. It is an error if @node is not an
+ * element.
+ *
+ * Returns a pointer to the attribute or NULL if arguments are invalid
+ * or a memory allocation failed.
*/
xmlAttrPtr
xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
@@ -1961,13 +1794,17 @@
/**
* xmlNewNsPropEatName:
- * @node: the holding node
- * @ns: the namespace
- * @name: the name of the attribute
- * @value: the value of the attribute
+ * @node: the parent node (optional)
+ * @ns: the namespace (optional)
+ * @name: the local name of the attribute
+ * @value: the value of the attribute (optional)
*
- * Create a new property tagged with a namespace and carried by a node.
- * Returns a pointer to the attribute
+ * Like xmlNewNsProp, but the @name string will be used directly
+ * without making a copy. Takes ownership of @name which will also
+ * be freed on error.
+ *
+ * Returns a pointer to the attribute or NULL if arguments are invalid
+ * or a memory allocation failed.
*/
xmlAttrPtr
xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
@@ -1982,17 +1819,19 @@
/**
* xmlNewDocProp:
- * @doc: the document
+ * @doc: the target document (optional)
* @name: the name of the attribute
- * @value: the value of the attribute
+ * @value: attribute value with XML references (optional)
*
- * Create a new property carried by a document.
- * NOTE: @value is supposed to be a piece of XML CDATA, so it allows entity
- * references, but XML special chars need to be escaped first by using
- * xmlEncodeEntitiesReentrant(). Use xmlNewProp() if you don't need
- * entities support.
+ * Create an attribute object.
*
- * Returns a pointer to the attribute
+ * If provided, @value is expected to be a valid XML attribute value
+ * possibly containing character and entity references. Syntax errors
+ * and references to undeclared entities are ignored silently.
+ * If you want to pass a raw string, see xmlNewProp.
+ *
+ * Returns a pointer to the attribute or NULL if arguments are invalid
+ * or a memory allocation failed.
*/
xmlAttrPtr
xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
@@ -2019,18 +1858,8 @@
goto error;
cur->doc = doc;
if (value != NULL) {
- xmlNodePtr tmp;
-
- cur->children = xmlStringGetNodeList(doc, value);
- cur->last = NULL;
-
- tmp = cur->children;
- while (tmp != NULL) {
- tmp->parent = (xmlNodePtr) cur;
- if (tmp->next == NULL)
- cur->last = tmp;
- tmp = tmp->next;
- }
+ if (xmlNodeParseContent((xmlNodePtr) cur, value, -1) < 0)
+ goto error;
}
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
@@ -2044,9 +1873,9 @@
/**
* xmlFreePropList:
- * @cur: the first property in the list
+ * @cur: the first attribute in the list
*
- * Free a property and all its siblings, all the children are freed too.
+ * Free an attribute list including all children.
*/
void
xmlFreePropList(xmlAttrPtr cur) {
@@ -2063,7 +1892,7 @@
* xmlFreeProp:
* @cur: an attribute
*
- * Free one attribute, all the content is freed too
+ * Free an attribute including all children.
*/
void
xmlFreeProp(xmlAttrPtr cur) {
@@ -2088,10 +1917,14 @@
* xmlRemoveProp:
* @cur: an attribute
*
- * Unlink and free one attribute, all the content is freed too
- * Note this doesn't work for namespace definition attributes
+ * Unlink and free an attribute including all children.
*
- * Returns 0 if success and -1 in case of error.
+ * Note this doesn't work for namespace declarations.
+ *
+ * The attribute must have a non-NULL parent pointer.
+ *
+ * Returns 0 on success or -1 if the attribute was not found or
+ * arguments are invalid.
*/
int
xmlRemoveProp(xmlAttrPtr cur) {
@@ -2125,12 +1958,14 @@
/**
* xmlNewDocPI:
- * @doc: the target document
- * @name: the processing instruction name
- * @content: the PI content
+ * @doc: the target document (optional)
+ * @name: the processing instruction target
+ * @content: the PI content (optional)
*
- * Creation of a processing instruction element.
- * Returns a pointer to the new node object.
+ * Create a processing instruction object.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
@@ -2173,14 +2008,15 @@
/**
* xmlNewPI:
- * @name: the processing instruction name
- * @content: the PI content
+ * @name: the processing instruction target
+ * @content: the PI content (optional)
*
- * Creation of a processing instruction element.
+ * Create a processing instruction node.
*
* Use of this function is DISCOURAGED in favor of xmlNewDocPI.
*
- * Returns a pointer to the new node object.
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewPI(const xmlChar *name, const xmlChar *content) {
@@ -2189,117 +2025,122 @@
/**
* xmlNewNode:
- * @ns: namespace if any
+ * @ns: namespace (optional)
* @name: the node name
*
- * Creation of a new node element. @ns is optional (NULL).
+ * Create an element node.
*
* Use of this function is DISCOURAGED in favor of xmlNewDocNode.
*
- * Returns a pointer to the new node object. Uses xmlStrdup() to make
- * copy of @name.
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
- xmlNodePtr cur;
-
- if (name == NULL) {
- return(NULL);
- }
-
- /*
- * Allocate a new node and fill the fields.
- */
- cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
- if (cur == NULL)
- return(NULL);
- memset(cur, 0, sizeof(xmlNode));
- cur->type = XML_ELEMENT_NODE;
-
- cur->name = xmlStrdup(name);
- if (cur->name == NULL)
- goto error;
- cur->ns = ns;
-
- if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
- xmlRegisterNodeDefaultValue(cur);
- return(cur);
-
-error:
- xmlFreeNode(cur);
- return(NULL);
+ return(xmlNewDocNode(NULL, ns, name, NULL));
}
/**
* xmlNewNodeEatName:
- * @ns: namespace if any
+ * @ns: namespace (optional)
* @name: the node name
*
- * Creation of a new node element. @ns is optional (NULL).
+ * Create an element node.
*
* Use of this function is DISCOURAGED in favor of xmlNewDocNodeEatName.
*
- * Returns a pointer to the new node object, with pointer @name as
- * new node's name. Use xmlNewNode() if a copy of @name string is
- * is needed as new node's name.
+ * Like xmlNewNode, but the @name string will be used directly
+ * without making a copy. Takes ownership of @name which will also
+ * be freed on error.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
+ return(xmlNewDocNodeEatName(NULL, ns, name, NULL));
+}
+
+static xmlNodePtr
+xmlNewElem(xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name,
+ const xmlChar *content) {
xmlNodePtr cur;
- if (name == NULL) {
- return(NULL);
- }
-
- /*
- * Allocate a new node and fill the fields.
- */
cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
if (cur == NULL)
return(NULL);
memset(cur, 0, sizeof(xmlNode));
- cur->type = XML_ELEMENT_NODE;
+ cur->type = XML_ELEMENT_NODE;
+ cur->doc = doc;
cur->name = name;
cur->ns = ns;
+ if (content != NULL) {
+ if (xmlNodeParseContent(cur, content, -1) < 0) {
+ /* Don't free name on error */
+ xmlFree(cur);
+ return(NULL);
+ }
+ }
+
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
+
return(cur);
}
/**
* xmlNewDocNode:
- * @doc: the document
- * @ns: namespace if any
+ * @doc: the target document
+ * @ns: namespace (optional)
* @name: the node name
- * @content: the XML text content if any
+ * @content: text content with XML references (optional)
*
- * Creation of a new node element within a document. @ns and @content
- * are optional (NULL).
- * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
- * references, but XML special chars need to be escaped first by using
- * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
- * need entities support.
+ * Create an element node.
*
- * Returns a pointer to the new node object.
+ * If provided, @content is expected to be a valid XML attribute value
+ * possibly containing character and entity references. Syntax errors
+ * and references to undeclared entities are ignored silently.
+ * Only references are handled, nested elements, comments or PIs are
+ * not. See xmlNewDocRawNode for an alternative.
+ *
+ * General notes on object creation:
+ *
+ * Each node and all its children are associated with the same
+ * document. The document should be provided when creating nodes to
+ * avoid a performance penalty when adding the node to a document
+ * tree. Note that a document only owns nodes reachable from the root
+ * node. Unlinked subtrees must be freed manually.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
const xmlChar *name, const xmlChar *content) {
xmlNodePtr cur;
+ xmlChar *copy;
- if ((doc != NULL) && (doc->dict != NULL))
- cur = xmlNewNodeEatName(ns, (xmlChar *)
- xmlDictLookup(doc->dict, name, -1));
- else
- cur = xmlNewNode(ns, name);
- if (cur != NULL) {
- cur->doc = doc;
- if (content != NULL) {
- cur->children = xmlStringGetNodeList(doc, content);
- UPDATE_LAST_CHILD_AND_PARENT(cur)
- }
+ if (name == NULL)
+ return(NULL);
+
+ if ((doc != NULL) && (doc->dict != NULL)) {
+ const xmlChar *dictName = xmlDictLookup(doc->dict, name, -1);
+
+ if (dictName == NULL)
+ return(NULL);
+ return(xmlNewElem(doc, ns, dictName, content));
+ }
+
+ copy = xmlStrdup(name);
+ if (copy == NULL)
+ return(NULL);
+
+ cur = xmlNewElem(doc, ns, copy, content);
+ if (cur == NULL) {
+ xmlFree(copy);
+ return(NULL);
}
return(cur);
@@ -2307,58 +2148,56 @@
/**
* xmlNewDocNodeEatName:
- * @doc: the document
- * @ns: namespace if any
+ * xmlNewDocNode:
+ * @doc: the target document
+ * @ns: namespace (optional)
* @name: the node name
- * @content: the XML text content if any
+ * @content: text content with XML references (optional)
*
- * Creation of a new node element within a document. @ns and @content
- * are optional (NULL).
- * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
- * references, but XML special chars need to be escaped first by using
- * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
- * need entities support.
+ * Create an element node.
*
- * Returns a pointer to the new node object.
+ * Like xmlNewDocNode, but the @name string will be used directly
+ * without making a copy. Takes ownership of @name which will also
+ * be freed on error.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
- xmlChar *name, const xmlChar *content) {
+ xmlChar *name, const xmlChar *content) {
xmlNodePtr cur;
- cur = xmlNewNodeEatName(ns, name);
- if (cur != NULL) {
- cur->doc = doc;
- if (content != NULL) {
- cur->children = xmlStringGetNodeList(doc, content);
- if (cur->children == NULL) {
- xmlFreeNode(cur);
- return(NULL);
- }
- UPDATE_LAST_CHILD_AND_PARENT(cur)
- }
- } else {
- /* if name don't come from the doc dictionary free it here */
- if ((name != NULL) &&
- ((doc == NULL) || (doc->dict == NULL) ||
- (!(xmlDictOwns(doc->dict, name)))))
- xmlFree(name);
+ if (name == NULL)
+ return(NULL);
+
+ cur = xmlNewElem(doc, ns, name, content);
+ if (cur == NULL) {
+ /* if name doesn't come from the doc dictionary free it here */
+ if ((doc == NULL) ||
+ (doc->dict == NULL) ||
+ (!xmlDictOwns(doc->dict, name)))
+ xmlFree(name);
+ return(NULL);
}
+
return(cur);
}
#ifdef LIBXML_TREE_ENABLED
/**
* xmlNewDocRawNode:
- * @doc: the document
- * @ns: namespace if any
+ * @doc: the target document
+ * @ns: namespace (optional)
* @name: the node name
- * @content: the text content if any
+ * @content: raw text content (optional)
*
- * Creation of a new node element within a document. @ns and @content
- * are optional (NULL).
+ * Create an element node.
*
- * Returns a pointer to the new node object.
+ * If provided, @value should be a raw, unescaped string.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
@@ -2369,8 +2208,17 @@
if (cur != NULL) {
cur->doc = doc;
if (content != NULL) {
- cur->children = xmlNewDocText(doc, content);
- UPDATE_LAST_CHILD_AND_PARENT(cur)
+ xmlNodePtr text;
+
+ text = xmlNewDocText(doc, content);
+ if (text == NULL) {
+ xmlFreeNode(cur);
+ return(NULL);
+ }
+
+ cur->children = text;
+ cur->last = text;
+ text->parent = cur;
}
}
return(cur);
@@ -2378,10 +2226,12 @@
/**
* xmlNewDocFragment:
- * @doc: the document owning the fragment
+ * @doc: the target document (optional)
*
- * Creation of a new Fragment node.
- * Returns a pointer to the new node object.
+ * Create a document fragment node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr
xmlNewDocFragment(xmlDocPtr doc) {
@@ -2406,13 +2256,14 @@
/**
* xmlNewText:
- * @content: the text content
+ * @content: raw text content (optional)
*
- * Creation of a new text node.
+ * Create a text node.
*
* Use of this function is DISCOURAGED in favor of xmlNewDocText.
*
- * Returns a pointer to the new node object.
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr
xmlNewText(const xmlChar *content) {
@@ -2447,62 +2298,52 @@
/**
* xmlNewTextChild:
* @parent: the parent node
- * @ns: a namespace if any
+ * @ns: a namespace (optional)
* @name: the name of the child
- * @content: the text content of the child if any.
+ * @content: raw text content of the child (optional)
*
- * Creation of a new child element, added at the end of @parent children list.
- * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
- * created element inherits the namespace of @parent. If @content is non NULL,
- * a child TEXT node will be created containing the string @content.
- * NOTE: Use xmlNewChild() if @content will contain entities that need to be
- * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
- * reserved XML chars that might appear in @content, such as the ampersand,
- * greater-than or less-than signs, are automatically replaced by their XML
- * escaped entity representations.
+ * Create a new child element and append it to a parent element.
*
- * Returns a pointer to the new node object.
+ * If @ns is NULL, the newly created element inherits the namespace
+ * of the parent.
+ *
+ * If @content is provided, a text node will be added to the child
+ * element, see xmlNewDocRawNode.
+ *
+ * Returns a pointer to the new node object or NULL if arguments
+ * are invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
const xmlChar *name, const xmlChar *content) {
xmlNodePtr cur, prev;
- if (parent == NULL) {
+ if ((parent == NULL) || (name == NULL))
return(NULL);
+
+ switch (parent->type) {
+ case XML_DOCUMENT_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+ case XML_DOCUMENT_FRAG_NODE:
+ break;
+
+ case XML_ELEMENT_NODE:
+ if (ns == NULL)
+ ns = parent->ns;
+ break;
+
+ default:
+ return(NULL);
}
- if (name == NULL) {
- return(NULL);
- }
-
- /*
- * Allocate a new node
- */
- if (parent->type == XML_ELEMENT_NODE) {
- if (ns == NULL)
- cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
- else
- cur = xmlNewDocRawNode(parent->doc, ns, name, content);
- } else if ((parent->type == XML_DOCUMENT_NODE) ||
- (parent->type == XML_HTML_DOCUMENT_NODE)) {
- if (ns == NULL)
- cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
- else
- cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
- } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
- cur = xmlNewDocRawNode( parent->doc, ns, name, content);
- } else {
- return(NULL);
- }
- if (cur == NULL) return(NULL);
+ cur = xmlNewDocRawNode(parent->doc, ns, name, content);
+ if (cur == NULL)
+ return(NULL);
/*
* add the new element at the end of the children list.
*/
- cur->type = XML_ELEMENT_NODE;
cur->parent = parent;
- cur->doc = parent->doc;
if (parent->children == NULL) {
parent->children = cur;
parent->last = cur;
@@ -2519,11 +2360,19 @@
/**
* xmlNewCharRef:
- * @doc: the document
- * @name: the char ref string, starting with # or "&# ... ;"
+ * @doc: the target document (optional)
+ * @name: the entity name
*
- * Creation of a new character reference node.
- * Returns a pointer to the new node object.
+ * This function is MISNAMED. It doesn't create a character reference
+ * but an entity reference.
+ *
+ * Create an empty entity reference node. This function doesn't attempt
+ * to look up the entity in @doc.
+ *
+ * Entity names like '&entity;' are handled as well.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
@@ -2566,11 +2415,16 @@
/**
* xmlNewReference:
- * @doc: the document
- * @name: the reference name, or the reference string with & and ;
+ * @doc: the target document (optional)
+ * @name: the entity name
*
- * Creation of a new reference node.
- * Returns a pointer to the new node object.
+ * Create a new entity reference node, linking the result with the
+ * entity in @doc if found.
+ *
+ * Entity names like '&entity;' are handled as well.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewReference(const xmlDoc *doc, const xmlChar *name) {
@@ -2626,11 +2480,13 @@
/**
* xmlNewDocText:
- * @doc: the document
- * @content: the text content
+ * @doc: the target document
+ * @content: raw text content (optional)
*
- * Creation of a new text node within a document.
- * Returns a pointer to the new node object.
+ * Create a new text node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr
xmlNewDocText(const xmlDoc *doc, const xmlChar *content) {
@@ -2643,13 +2499,13 @@
/**
* xmlNewTextLen:
- * @content: the text content
- * @len: the text len.
+ * @content: raw text content (optional)
+ * @len: size of text content
*
* Use of this function is DISCOURAGED in favor of xmlNewDocTextLen.
*
- * Creation of a new text node with an extra parameter for the content's length
- * Returns a pointer to the new node object.
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr
xmlNewTextLen(const xmlChar *content, int len) {
@@ -2667,6 +2523,10 @@
cur->name = xmlStringText;
if (content != NULL) {
cur->content = xmlStrndup(content, len);
+ if (cur->content == NULL) {
+ xmlFreeNode(cur);
+ return(NULL);
+ }
}
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
@@ -2676,13 +2536,14 @@
/**
* xmlNewDocTextLen:
- * @doc: the document
- * @content: the text content
- * @len: the text len.
+ * @doc: the target document
+ * @content: raw text content (optional)
+ * @len: size of text content
*
- * Creation of a new text node with an extra content length parameter. The
- * text node pertain to a given document.
- * Returns a pointer to the new node object.
+ * Create a new text node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr
xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
@@ -2695,12 +2556,14 @@
/**
* xmlNewComment:
- * @content: the comment content
+ * @content: the comment content (optional)
*
* Use of this function is DISCOURAGED in favor of xmlNewDocComment.
*
- * Creation of a new node containing a comment.
- * Returns a pointer to the new node object.
+ * Create a comment node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr
xmlNewComment(const xmlChar *content) {
@@ -2733,12 +2596,14 @@
/**
* xmlNewCDataBlock:
- * @doc: the document
- * @content: the CDATA block content content
- * @len: the length of the block
+ * @doc: the target document (optional)
+ * @content: raw text content (optional)
+ * @len: size of text content
*
- * Creation of a new node containing a CDATA block.
- * Returns a pointer to the new node object.
+ * Create a CDATA section node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr
xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
@@ -2772,8 +2637,10 @@
* @doc: the document
* @content: the comment content
*
- * Creation of a new node containing a comment within a document.
- * Returns a pointer to the new node object.
+ * Create a comment node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr
xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
@@ -2784,166 +2651,231 @@
return(cur);
}
-static const xmlChar *_copyStringForNewDictIfNeeded(xmlDictPtr oldDict, xmlDictPtr newDict, const xmlChar *oldValue) {
- const xmlChar *newValue = oldValue;
- if (oldValue) {
- int oldDictOwnsOldValue = oldDict && (xmlDictOwns(oldDict, oldValue) == 1);
- if (oldDictOwnsOldValue) {
+static int
+xmlNodeSetDoc(xmlNodePtr node, xmlDocPtr doc) {
+ xmlDocPtr oldDoc;
+ xmlDictPtr oldDict, newDict;
+ int ret = 0;
+
+ /*
+ * Remove name and content from old dictionary
+ */
+
+ oldDoc = node->doc;
+ oldDict = oldDoc ? oldDoc->dict : NULL;
+ newDict = doc ? doc->dict : NULL;
+
+ if ((oldDict != NULL) && (oldDict != newDict)) {
+ if ((node->name != NULL) &&
+ ((node->type == XML_ELEMENT_NODE) ||
+ (node->type == XML_ATTRIBUTE_NODE) ||
+ (node->type == XML_PI_NODE) ||
+ (node->type == XML_ENTITY_REF_NODE)) &&
+ (xmlDictOwns(oldDict, node->name))) {
if (newDict)
- newValue = xmlDictLookup(newDict, oldValue, -1);
+ node->name = xmlDictLookup(newDict, node->name, -1);
else
- newValue = xmlStrdup(oldValue);
+ node->name = xmlStrdup(node->name);
+ if (node->name == NULL)
+ ret = -1;
+ }
+
+ if ((node->content != NULL) &&
+ ((node->type == XML_TEXT_NODE) ||
+ (node->type == XML_CDATA_SECTION_NODE)) &&
+ (xmlDictOwns(oldDict, node->content))) {
+ node->content = xmlStrdup(node->content);
+ if (node->content == NULL)
+ ret = -1;
}
}
- return newValue;
+
+ /*
+ * Handle IDs
+ *
+ * TODO: ID attributes should also be added to the new
+ * document, but it's not clear how to handle clashes.
+ */
+ if (node->type == XML_ATTRIBUTE_NODE) {
+ xmlAttrPtr attr = (xmlAttrPtr) node;
+
+ if (attr->atype == XML_ATTRIBUTE_ID)
+ xmlRemoveID(oldDoc, attr);
+ }
+
+ /*
+ * Handle entity references
+ */
+ if (node->type == XML_ENTITY_REF_NODE) {
+ node->children = NULL;
+ node->last = NULL;
+ node->content = NULL;
+
+ if ((doc != NULL) &&
+ ((doc->intSubset != NULL) || (doc->extSubset != NULL))) {
+ xmlEntityPtr ent;
+
+ /*
+ * Assign new entity node if available
+ */
+ ent = xmlGetDocEntity(doc, node->name);
+ if (ent != NULL) {
+ node->children = (xmlNodePtr) ent;
+ node->last = (xmlNodePtr) ent;
+ node->content = ent->content;
+ }
+ }
+ }
+
+ /*
+ * Set new document
+ */
+ node->doc = doc;
+
+ return(ret);
}
/**
* xmlSetTreeDoc:
- * @tree: the top element
- * @doc: the document
+ * @tree: root of a subtree
+ * @doc: new document
*
- * update all nodes under the tree to point to the right document
+ * This is an internal function which shouldn't be used. It is
+ * invoked by functions like xmlAddChild, xmlAddSibling or
+ * xmlReplaceNode. @tree must be the root node of an unlinked
+ * subtree.
+ *
+ * Associate all nodes in a tree with a new document.
+ *
+ * Also copy strings from the old document's dictionary and
+ * remove ID attributes from the old ID table.
+ *
+ * Returns 0 on success. If a memory allocation fails, returns -1.
+ * The whole tree will be updated on failure but some strings
+ * may be lost.
*/
-void
+int
xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
- xmlAttrPtr prop;
+ int ret = 0;
if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
- return;
- if (tree->doc != doc) {
- xmlDictPtr oldTreeDict = tree->doc ? tree->doc->dict : NULL;
- xmlDictPtr newDict = doc ? doc->dict : NULL;
+ return(0);
+ if (tree->doc == doc)
+ return(0);
- if(tree->type == XML_ELEMENT_NODE) {
- prop = tree->properties;
- while (prop != NULL) {
- if (prop->atype == XML_ATTRIBUTE_ID) {
- xmlRemoveID(tree->doc, prop);
- }
+ if (tree->type == XML_ELEMENT_NODE) {
+ xmlAttrPtr prop = tree->properties;
- if (prop->doc != doc) {
- xmlDictPtr oldPropDict = prop->doc ? prop->doc->dict : NULL;
- /* TODO: malloc check */
- prop->name = _copyStringForNewDictIfNeeded(oldPropDict, newDict, prop->name);
- prop->doc = doc;
- }
- xmlSetListDoc(prop->children, doc);
+ while (prop != NULL) {
+ if (prop->children != NULL) {
+ if (xmlSetListDoc(prop->children, doc) < 0)
+ ret = -1;
+ }
- /*
- * TODO: ID attributes should be also added to the new
- * document, but this breaks things like xmlReplaceNode.
- * The underlying problem is that xmlRemoveID is only called
- * if a node is destroyed, not if it's unlinked.
- */
-#if 0
- if (xmlIsID(doc, tree, prop)) {
- xmlChar *idVal = xmlNodeListGetString(doc, prop->children,
- 1);
- xmlAddID(NULL, doc, idVal, prop);
- }
-#endif
+ if (xmlNodeSetDoc((xmlNodePtr) prop, doc) < 0)
+ ret = -1;
- prop = prop->next;
- }
- }
- if (tree->type == XML_ENTITY_REF_NODE) {
- /*
- * Clear 'children' which points to the entity declaration
- * from the original document.
- */
- tree->children = NULL;
- } else if (tree->children != NULL) {
- xmlSetListDoc(tree->children, doc);
+ prop = prop->next;
}
-
- /* TODO: malloc check */
- tree->name = _copyStringForNewDictIfNeeded(oldTreeDict, newDict, tree->name);
- tree->content = (xmlChar *)_copyStringForNewDictIfNeeded(oldTreeDict, NULL, tree->content);
- /* FIXME: tree->ns should be updated as in xmlStaticCopyNode(). */
- tree->doc = doc;
}
+
+ if ((tree->children != NULL) &&
+ (tree->type != XML_ENTITY_REF_NODE)) {
+ if (xmlSetListDoc(tree->children, doc) < 0)
+ ret = -1;
+ }
+
+ if (xmlNodeSetDoc(tree, doc) < 0)
+ ret = -1;
+
+ return(ret);
}
/**
* xmlSetListDoc:
- * @list: the first element
- * @doc: the document
+ * @list: a node list
+ * @doc: new document
*
- * update all nodes in the list to point to the right document
+ * Associate all subtrees in @list with a new document.
+ *
+ * Internal function, see xmlSetTreeDoc.
+ *
+ * Returns 0 on success. If a memory allocation fails, returns -1.
+ * All subtrees will be updated on failure but some strings
+ * may be lost.
*/
-void
+int
xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
xmlNodePtr cur;
+ int ret = 0;
if ((list == NULL) || (list->type == XML_NAMESPACE_DECL))
- return;
+ return(0);
+
cur = list;
while (cur != NULL) {
- if (cur->doc != doc)
- xmlSetTreeDoc(cur, doc);
+ if (cur->doc != doc) {
+ if (xmlSetTreeDoc(cur, doc) < 0)
+ ret = -1;
+ }
cur = cur->next;
}
+
+ return(ret);
}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
/**
* xmlNewChild:
* @parent: the parent node
- * @ns: a namespace if any
+ * @ns: a namespace (optional)
* @name: the name of the child
- * @content: the XML content of the child if any.
+ * @content: text content with XML references (optional)
*
- * Creation of a new child element, added at the end of @parent children list.
- * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
- * created element inherits the namespace of @parent. If @content is non NULL,
- * a child list containing the TEXTs and ENTITY_REFs node will be created.
- * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
- * references. XML special chars must be escaped first by using
- * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
+ * Create a new child element and append it to a parent element.
*
- * Returns a pointer to the new node object.
+ * If @ns is NULL, the newly created element inherits the namespace
+ * of the parent.
+ *
+ * If provided, @content is expected to be a valid XML attribute
+ * value possibly containing character and entity references. Text
+ * and entity reference node will be added to the child element,
+ * see xmlNewDocNode.
+ *
+ * Returns a pointer to the new node object or NULL if arguments
+ * are invalid or a memory allocation failed.
*/
xmlNodePtr
xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
const xmlChar *name, const xmlChar *content) {
xmlNodePtr cur, prev;
- if (parent == NULL) {
+ if ((parent == NULL) || (name == NULL))
return(NULL);
+
+ switch (parent->type) {
+ case XML_DOCUMENT_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+ case XML_DOCUMENT_FRAG_NODE:
+ break;
+
+ case XML_ELEMENT_NODE:
+ if (ns == NULL)
+ ns = parent->ns;
+ break;
+
+ default:
+ return(NULL);
}
- if (name == NULL) {
- return(NULL);
- }
-
- /*
- * Allocate a new node
- */
- if (parent->type == XML_ELEMENT_NODE) {
- if (ns == NULL)
- cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
- else
- cur = xmlNewDocNode(parent->doc, ns, name, content);
- } else if ((parent->type == XML_DOCUMENT_NODE) ||
- (parent->type == XML_HTML_DOCUMENT_NODE)) {
- if (ns == NULL)
- cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
- else
- cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
- } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
- cur = xmlNewDocNode( parent->doc, ns, name, content);
- } else {
- return(NULL);
- }
- if (cur == NULL) return(NULL);
+ cur = xmlNewDocNode(parent->doc, ns, name, content);
+ if (cur == NULL)
+ return(NULL);
/*
* add the new element at the end of the children list.
*/
- cur->type = XML_ELEMENT_NODE;
cur->parent = parent;
- cur->doc = parent->doc;
if (parent->children == NULL) {
parent->children = cur;
parent->last = cur;
@@ -2958,263 +2890,252 @@
}
#endif /* LIBXML_TREE_ENABLED */
-/**
- * xmlAddPropSibling:
- * @prev: the attribute to which @prop is added after
- * @cur: the base attribute passed to calling function
- * @prop: the new attribute
- *
- * Add a new attribute after @prev using @cur as base attribute.
- * When inserting before @cur, @prev is passed as @cur->prev.
- * When inserting after @cur, @prev is passed as @cur.
- * If an existing attribute is found it is destroyed prior to adding @prop.
- *
- * See the note regarding namespaces in xmlAddChild.
- *
- * Returns the attribute being inserted or NULL in case of error.
- */
+static void
+xmlTextSetContent(xmlNodePtr text, xmlChar *content) {
+ if ((text->content != NULL) &&
+ (text->content != (xmlChar *) &text->properties)) {
+ xmlDocPtr doc = text->doc;
+
+ if ((doc == NULL) ||
+ (doc->dict == NULL) ||
+ (!xmlDictOwns(doc->dict, text->content)))
+ xmlFree(text->content);
+ }
+
+ text->content = content;
+ text->properties = NULL;
+}
+
+static int
+xmlTextAddContent(xmlNodePtr text, const xmlChar *content, int len) {
+ xmlChar *merged;
+
+ if (content == NULL)
+ return(0);
+
+ merged = xmlStrncatNew(text->content, content, len);
+ if (merged == NULL)
+ return(-1);
+
+ xmlTextSetContent(text, merged);
+ return(0);
+}
+
static xmlNodePtr
-xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
- xmlAttrPtr attr;
+xmlInsertProp(xmlDocPtr doc, xmlNodePtr cur, xmlNodePtr parent,
+ xmlNodePtr prev, xmlNodePtr next) {
+ xmlAttrPtr attr;
- if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) ||
- (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) ||
- ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)))
- return(NULL);
+ if (((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)) ||
+ ((next != NULL) && (next->type != XML_ATTRIBUTE_NODE)))
+ return(NULL);
- /* check if an attribute with the same name exists */
- if (prop->ns == NULL)
- attr = xmlHasNsProp(cur->parent, prop->name, NULL);
- else
- attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
+ /* check if an attribute with the same name exists */
+ attr = xmlGetPropNodeInternal(parent, cur->name,
+ cur->ns ? cur->ns->href : NULL, 0);
- if (prop->doc != cur->doc) {
- xmlSetTreeDoc(prop, cur->doc);
+ xmlUnlinkNode(cur);
+
+ if (cur->doc != doc) {
+ if (xmlSetTreeDoc(cur, doc) < 0)
+ return(NULL);
+ }
+
+ cur->parent = parent;
+ cur->prev = prev;
+ cur->next = next;
+
+ if (prev == NULL) {
+ if (parent != NULL)
+ parent->properties = (xmlAttrPtr) cur;
+ } else {
+ prev->next = cur;
+ }
+ if (next != NULL) {
+ next->prev = cur;
+ }
+
+ if ((attr != NULL) && (attr != (xmlAttrPtr) cur)) {
+ /* different instance, destroy it (attributes must be unique) */
+ xmlRemoveProp((xmlAttrPtr) attr);
+ }
+
+ return cur;
+}
+
+static xmlNodePtr
+xmlInsertNode(xmlDocPtr doc, xmlNodePtr cur, xmlNodePtr parent,
+ xmlNodePtr prev, xmlNodePtr next) {
+ if (cur->type == XML_ATTRIBUTE_NODE)
+ return xmlInsertProp(doc, cur, parent, prev, next);
+
+ xmlUnlinkNode(cur);
+
+ /*
+ * Coalesce text nodes
+ */
+ if (cur->type == XML_TEXT_NODE) {
+ if ((prev != NULL) && (prev->type == XML_TEXT_NODE) &&
+ (prev->name == cur->name)) {
+ if (xmlTextAddContent(prev, cur->content, -1) < 0)
+ return(NULL);
+ xmlFreeNode(cur);
+ return(prev);
}
- prop->parent = cur->parent;
- prop->prev = prev;
- if (prev != NULL) {
- prop->next = prev->next;
- prev->next = prop;
- if (prop->next)
- prop->next->prev = prop;
- } else {
- prop->next = cur;
- cur->prev = prop;
+
+ if ((next != NULL) && (next->type == XML_TEXT_NODE) &&
+ (next->name == cur->name)) {
+ if (cur->content != NULL) {
+ xmlChar *merged;
+
+ merged = xmlStrncatNew(cur->content, next->content, -1);
+ if (merged == NULL)
+ return(NULL);
+ xmlTextSetContent(next, merged);
+ }
+
+ xmlFreeNode(cur);
+ return(next);
}
- if (prop->prev == NULL && prop->parent != NULL)
- prop->parent->properties = (xmlAttrPtr) prop;
- if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
- /* different instance, destroy it (attributes must be unique) */
- xmlRemoveProp((xmlAttrPtr) attr);
- }
- return prop;
+ }
+
+ if (cur->doc != doc) {
+ if (xmlSetTreeDoc(cur, doc) < 0)
+ return(NULL);
+ }
+
+ cur->parent = parent;
+ cur->prev = prev;
+ cur->next = next;
+
+ if (prev == NULL) {
+ if (parent != NULL)
+ parent->children = cur;
+ } else {
+ prev->next = cur;
+ }
+ if (next == NULL) {
+ if (parent != NULL)
+ parent->last = cur;
+ } else {
+ next->prev = cur;
+ }
+
+ return(cur);
}
/**
* xmlAddNextSibling:
- * @cur: the child node
- * @elem: the new node
+ * @prev: the target node
+ * @cur: the new node
*
- * Add a new node @elem as the next sibling of @cur
- * If the new node was already inserted in a document it is
- * first unlinked from its existing context.
- * As a result of text merging @elem may be freed.
- * If the new node is ATTRIBUTE, it is added into properties instead of children.
- * If there is an attribute with equal name, it is first destroyed.
+ * Unlinks @cur and inserts it as next sibling after @prev.
*
- * See the note regarding namespaces in xmlAddChild.
+ * If @cur is a text node, it may be merged with an adjacent text
+ * node and freed. In this case the text node containing the merged
+ * content is returned.
*
- * Returns the new node or NULL in case of error.
+ * If @cur is an attribute node, it is inserted after attribute
+ * @prev. If the attribute list contains an attribute with a name
+ * matching @cur, the old attribute is destroyed.
+ *
+ * See the notes in xmlAddChild.
+ *
+ * Returns @cur or a sibling if @cur was merged. Returns NULL
+ * if arguments are invalid or a memory allocation failed.
*/
xmlNodePtr
-xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
- if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
+xmlAddNextSibling(xmlNodePtr prev, xmlNodePtr cur) {
+ if ((prev == NULL) || (prev->type == XML_NAMESPACE_DECL) ||
+ (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) ||
+ (cur == prev))
return(NULL);
- }
- if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
- return(NULL);
- }
- if (cur == elem) {
- return(NULL);
- }
+ if (cur == prev->next)
+ return(cur);
- xmlUnlinkNode(elem);
-
- if (elem->type == XML_TEXT_NODE) {
- if (cur->type == XML_TEXT_NODE) {
- xmlNodeAddContent(cur, elem->content);
- xmlFreeNode(elem);
- return(cur);
- }
- if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
- (cur->name == cur->next->name)) {
- xmlChar *tmp;
-
- /* TODO: malloc check */
- tmp = xmlStrdup(elem->content);
- tmp = xmlStrcat(tmp, cur->next->content);
- xmlNodeSetContent(cur->next, tmp);
- xmlFree(tmp);
- xmlFreeNode(elem);
- return(cur->next);
- }
- } else if (elem->type == XML_ATTRIBUTE_NODE) {
- return xmlAddPropSibling(cur, cur, elem);
- }
-
- if (elem->doc != cur->doc) {
- xmlSetTreeDoc(elem, cur->doc);
- }
- elem->parent = cur->parent;
- elem->prev = cur;
- elem->next = cur->next;
- cur->next = elem;
- if (elem->next != NULL)
- elem->next->prev = elem;
- if ((elem->parent != NULL) && (elem->parent->last == cur))
- elem->parent->last = elem;
- return(elem);
+ return(xmlInsertNode(prev->doc, cur, prev->parent, prev, prev->next));
}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
/**
* xmlAddPrevSibling:
- * @cur: the child node
- * @elem: the new node
+ * @next: the target node
+ * @cur: the new node
*
- * Add a new node @elem as the previous sibling of @cur
- * merging adjacent TEXT nodes (@elem may be freed)
- * If the new node was already inserted in a document it is
- * first unlinked from its existing context.
- * If the new node is ATTRIBUTE, it is added into properties instead of children.
- * If there is an attribute with equal name, it is first destroyed.
+ * Unlinks @cur and inserts it as previous sibling before @next.
*
- * See the note regarding namespaces in xmlAddChild.
+ * If @cur is a text node, it may be merged with an adjacent text
+ * node and freed. In this case the text node containing the merged
+ * content is returned.
*
- * Returns the new node or NULL in case of error.
+ * If @cur is an attribute node, it is inserted before attribute
+ * @next. If the attribute list contains an attribute with a name
+ * matching @cur, the old attribute is destroyed.
+ *
+ * See the notes in xmlAddChild.
+ *
+ * Returns @cur or a sibling if @cur was merged. Returns NULL
+ * if arguments are invalid or a memory allocation failed.
*/
xmlNodePtr
-xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
- if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
+xmlAddPrevSibling(xmlNodePtr next, xmlNodePtr cur) {
+ if ((next == NULL) || (next->type == XML_NAMESPACE_DECL) ||
+ (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) ||
+ (cur == next))
return(NULL);
- }
- if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
- return(NULL);
- }
- if (cur == elem) {
- return(NULL);
- }
+ if (cur == next->prev)
+ return(cur);
- xmlUnlinkNode(elem);
-
- if (elem->type == XML_TEXT_NODE) {
- if (cur->type == XML_TEXT_NODE) {
- xmlChar *tmp;
-
- /* TODO: malloc check */
- tmp = xmlStrdup(elem->content);
- tmp = xmlStrcat(tmp, cur->content);
- xmlNodeSetContent(cur, tmp);
- xmlFree(tmp);
- xmlFreeNode(elem);
- return(cur);
- }
- if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
- (cur->name == cur->prev->name)) {
- xmlNodeAddContent(cur->prev, elem->content);
- xmlFreeNode(elem);
- return(cur->prev);
- }
- } else if (elem->type == XML_ATTRIBUTE_NODE) {
- return xmlAddPropSibling(cur->prev, cur, elem);
- }
-
- if (elem->doc != cur->doc) {
- xmlSetTreeDoc(elem, cur->doc);
- }
- elem->parent = cur->parent;
- elem->next = cur;
- elem->prev = cur->prev;
- cur->prev = elem;
- if (elem->prev != NULL)
- elem->prev->next = elem;
- if ((elem->parent != NULL) && (elem->parent->children == cur)) {
- elem->parent->children = elem;
- }
- return(elem);
+ return(xmlInsertNode(next->doc, cur, next->parent, next->prev, next));
}
#endif /* LIBXML_TREE_ENABLED */
/**
* xmlAddSibling:
- * @cur: the child node
- * @elem: the new node
+ * @node: the target node
+ * @cur: the new node
*
- * Add a new element @elem to the list of siblings of @cur
- * merging adjacent TEXT nodes (@elem may be freed)
- * If the new element was already inserted in a document it is
- * first unlinked from its existing context.
+ * Unlinks @cur and inserts it as last sibling of @node.
*
- * See the note regarding namespaces in xmlAddChild.
+ * If @cur is a text node, it may be merged with an adjacent text
+ * node and freed. In this case the text node containing the merged
+ * content is returned.
*
- * Returns the new element or NULL in case of error.
+ * If @cur is an attribute node, it is appended to the attribute
+ * list containing @node. If the attribute list contains an attribute
+ * with a name matching @cur, the old attribute is destroyed.
+ *
+ * See the notes in xmlAddChild.
+ *
+ * Returns @cur or a sibling if @cur was merged. Returns NULL
+ * if arguments are invalid or a memory allocation failed.
*/
xmlNodePtr
-xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
- xmlNodePtr parent;
-
- if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
+xmlAddSibling(xmlNodePtr node, xmlNodePtr cur) {
+ if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
+ (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) ||
+ (cur == node))
return(NULL);
- }
-
- if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
- return(NULL);
- }
-
- if (cur == elem) {
- return(NULL);
- }
/*
* Constant time is we can rely on the ->parent->last to find
* the last sibling.
*/
- if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
- (cur->parent->children != NULL) &&
- (cur->parent->last != NULL) &&
- (cur->parent->last->next == NULL)) {
- cur = cur->parent->last;
+ if ((node->type != XML_ATTRIBUTE_NODE) && (node->parent != NULL)) {
+ if (node->parent->last != NULL)
+ node = node->parent->last;
} else {
- while (cur->next != NULL) cur = cur->next;
+ while (node->next != NULL)
+ node = node->next;
}
- xmlUnlinkNode(elem);
+ if (cur == node)
+ return(cur);
- if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
- (cur->name == elem->name)) {
- xmlNodeAddContent(cur, elem->content);
- xmlFreeNode(elem);
- return(cur);
- } else if (elem->type == XML_ATTRIBUTE_NODE) {
- return xmlAddPropSibling(cur, cur, elem);
- }
-
- if (elem->doc != cur->doc) {
- xmlSetTreeDoc(elem, cur->doc);
- }
- parent = cur->parent;
- elem->prev = cur;
- elem->next = NULL;
- elem->parent = parent;
- cur->next = elem;
- if (parent != NULL)
- parent->last = elem;
-
- return(elem);
+ return(xmlInsertNode(node->doc, cur, node->parent, node, NULL));
}
/**
@@ -3222,16 +3143,17 @@
* @parent: the parent node
* @cur: the first node in the list
*
- * Add a list of node at the end of the child list of the parent
- * merging adjacent TEXT nodes (@cur may be freed)
+ * Append a node list to another node.
*
- * See the note regarding namespaces in xmlAddChild.
+ * See xmlAddChild.
*
* Returns the last child or NULL in case of error.
*/
xmlNodePtr
xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
+ xmlNodePtr iter;
xmlNodePtr prev;
+ int oom;
if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
return(NULL);
@@ -3241,9 +3163,15 @@
return(NULL);
}
- if ((cur->doc != NULL) && (parent->doc != NULL) &&
- (cur->doc != parent->doc)) {
+ oom = 0;
+ for (iter = cur; iter != NULL; iter = iter->next) {
+ if (iter->doc != parent->doc) {
+ if (xmlSetTreeDoc(iter, parent->doc) < 0)
+ oom = 1;
+ }
}
+ if (oom)
+ return(NULL);
/*
* add the first element at the end of the children list.
@@ -3252,40 +3180,36 @@
if (parent->children == NULL) {
parent->children = cur;
} else {
+ prev = parent->last;
+
/*
* If cur and parent->last both are TEXT nodes, then merge them.
*/
if ((cur->type == XML_TEXT_NODE) &&
- (parent->last->type == XML_TEXT_NODE) &&
- (cur->name == parent->last->name)) {
- xmlNodeAddContent(parent->last, cur->content);
+ (prev->type == XML_TEXT_NODE) &&
+ (cur->name == prev->name)) {
+ xmlNodePtr next;
+
+ if (xmlTextAddContent(prev, cur->content, -1) < 0)
+ return(NULL);
+ next = cur->next;
+ xmlFreeNode(cur);
/*
* if it's the only child, nothing more to be done.
*/
- if (cur->next == NULL) {
- xmlFreeNode(cur);
- return(parent->last);
- }
- prev = cur;
- cur = cur->next;
- xmlFreeNode(prev);
+ if (next == NULL)
+ return(prev);
+ cur = next;
}
- prev = parent->last;
+
prev->next = cur;
cur->prev = prev;
}
while (cur->next != NULL) {
cur->parent = parent;
- if (cur->doc != parent->doc) {
- xmlSetTreeDoc(cur, parent->doc);
- }
cur = cur->next;
}
cur->parent = parent;
- /* the parent may not be linked to a doc ! */
- if (cur->doc != parent->doc) {
- xmlSetTreeDoc(cur, parent->doc);
- }
parent->last = cur;
return(cur);
@@ -3296,18 +3220,41 @@
* @parent: the parent node
* @cur: the child node
*
- * Add a new node to @parent, at the end of the child (or property) list
- * merging adjacent TEXT nodes (in which case @cur is freed)
- * If the new node is ATTRIBUTE, it is added into properties instead of children.
- * If there is an attribute with equal name, it is first destroyed.
+ * Append @cur to the children of @parent.
*
- * All tree manipulation functions can safely move nodes within a document.
- * But when moving nodes from one document to another, references to
- * namespaces in element or attribute nodes are NOT fixed. In this case,
- * you MUST call xmlReconciliateNs after the move operation to avoid
- * memory errors.
+ * Unlike functions like xmlAddSibling, this function doesn't unlink
+ * @cur before appending. It is an error if @cur has siblings or a
+ * parent. This behavior might change in future releases.
*
- * Returns the child or NULL in case of error.
+ * If @cur is a text node, it may be merged with an adjacent text
+ * node and freed. In this case the text node containing the merged
+ * content is returned.
+ *
+ * If @cur is an attribute node, it is appended to the attributes of
+ * @parent. If the attribute list contains an attribute with a name
+ * matching @elem, the old attribute is destroyed.
+ *
+ * General notes:
+ *
+ * Move operations like xmlAddChild can cause element or attribute
+ * nodes to reference namespaces that aren't declared in one of
+ * their ancestors. This can lead to use-after-free errors if the
+ * elements containing the declarations are freed later, especially
+ * when moving nodes from one document to another. You should
+ * consider calling xmlReconciliateNs after a move operation to
+ * normalize namespaces. Another option is to call
+ * xmlDOMWrapAdoptNode with the target parent before moving a node.
+ *
+ * For the most part, move operations don't check whether the
+ * resulting tree structure is valid. Users must make sure that
+ * parent nodes only receive children of valid types. Inserted
+ * child nodes must never be an ancestor of the parent node to
+ * avoid cycles in the tree structure. In general, only
+ * document, document fragments, elements and attributes
+ * should be used as parent nodes.
+ *
+ * Returns @elem or a sibling if @elem was merged. Returns NULL
+ * if arguments are invalid or a memory allocation failed.
*/
xmlNodePtr
xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
@@ -3317,86 +3264,75 @@
return(NULL);
}
- if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
+ if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL) ||
+ (cur->next != NULL) || (cur->prev != NULL) ||
+ ((cur->parent != NULL && cur->parent != parent))) {
return(NULL);
}
if (parent == cur) {
return(NULL);
}
+
+ /*
+ * Handle text parent
+ */
+ if (parent->type == XML_TEXT_NODE) {
+ if (xmlTextAddContent(parent, cur->content, -1) < 0)
+ return(NULL);
+ xmlFreeNode(cur);
+ return(parent);
+ }
+
/*
* If cur is a TEXT node, merge its content with adjacent TEXT nodes
* cur is then freed.
*/
if (cur->type == XML_TEXT_NODE) {
- if ((parent->type == XML_TEXT_NODE) &&
- (parent->content != NULL) &&
- (parent->name == cur->name)) {
- if (xmlNodeAddContent(parent, cur->content) != 0) {
- xmlFreeNode(cur);
+ xmlNodePtr last = parent->last;
+
+ if ((last != NULL) && (last->type == XML_TEXT_NODE) &&
+ (last->name == cur->name) &&
+ (last != cur)) {
+ if (xmlTextAddContent(last, cur->content, -1) < 0)
return(NULL);
- }
xmlFreeNode(cur);
- return(parent);
+ return(last);
}
- if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
- (parent->last->name == cur->name) &&
- (parent->last != cur)) {
- if (xmlNodeAddContent(parent->last, cur->content) != 0) {
- xmlFreeNode(cur);
- return(NULL);
- }
- xmlFreeNode(cur);
- return(parent->last);
- }
+ } else if (cur->type == XML_ATTRIBUTE_NODE) {
+ if (parent->type != XML_ELEMENT_NODE)
+ return(NULL);
}
/*
* add the new element at the end of the children list.
*/
prev = cur->parent;
- cur->parent = parent;
if (cur->doc != parent->doc) {
- xmlSetTreeDoc(cur, parent->doc);
+ if (xmlSetTreeDoc(cur, parent->doc) < 0)
+ return(NULL);
}
+ cur->parent = parent;
/* this check prevents a loop on tree-traversions if a developer
* tries to add a node to its parent multiple times
*/
if (prev == parent)
return(cur);
- /*
- * Coalescing
- */
- if ((parent->type == XML_TEXT_NODE) &&
- (parent->content != NULL) &&
- (parent != cur)) {
- if (xmlNodeAddContent(parent, cur->content) != 0) {
- xmlFreeNode(cur);
- return(NULL);
- }
- xmlFreeNode(cur);
- return(parent);
- }
if (cur->type == XML_ATTRIBUTE_NODE) {
- if (parent->type != XML_ELEMENT_NODE)
- return(NULL);
if (parent->properties != NULL) {
/* check if an attribute with the same name exists */
xmlAttrPtr lastattr;
- if (cur->ns == NULL)
- lastattr = xmlHasNsProp(parent, cur->name, NULL);
- else
- lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
- if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
+ lastattr = xmlGetPropNodeInternal(parent, cur->name,
+ cur->ns ? cur->ns->href : NULL, 0);
+ if (lastattr != NULL) {
+ if (lastattr == (xmlAttrPtr) cur)
+ return(cur);
/* different instance, destroy it (attributes must be unique) */
- xmlUnlinkNode((xmlNodePtr) lastattr);
+ xmlUnlinkNode((xmlNodePtr) lastattr);
xmlFreeProp(lastattr);
}
- if (lastattr == (xmlAttrPtr) cur)
- return(cur);
-
}
if (parent->properties == NULL) {
parent->properties = (xmlAttrPtr) cur;
@@ -3427,8 +3363,9 @@
* xmlGetLastChild:
* @parent: the parent node
*
- * Search the last child of a node.
- * Returns the last child or NULL if none.
+ * Find the last child of a node.
+ *
+ * Returns the last child or NULL if parent has no children.
*/
xmlNodePtr
xmlGetLastChild(const xmlNode *parent) {
@@ -3447,13 +3384,12 @@
* xmlChildElementCount:
* @parent: the parent node
*
- * Finds the current number of child nodes of that element which are
- * element nodes.
- * Note the handling of entities references is different than in
- * the W3C DOM element traversal spec since we don't have back reference
- * from entities content to entities references.
+ * Count the number of child nodes which are elements.
*
- * Returns the count of element child or 0 if not available
+ * Note that entity references are not expanded.
+ *
+ * Returns the number of element children or 0 if arguments are
+ * invalid.
*/
unsigned long
xmlChildElementCount(xmlNodePtr parent) {
@@ -3464,10 +3400,10 @@
return(0);
switch (parent->type) {
case XML_ELEMENT_NODE:
- case XML_ENTITY_NODE:
case XML_DOCUMENT_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_HTML_DOCUMENT_NODE:
+ case XML_ENTITY_DECL:
cur = parent->children;
break;
default:
@@ -3485,12 +3421,11 @@
* xmlFirstElementChild:
* @parent: the parent node
*
- * Finds the first child node of that element which is a Element node
- * Note the handling of entities references is different than in
- * the W3C DOM element traversal spec since we don't have back reference
- * from entities content to entities references.
+ * Find the first child node which is an element.
*
- * Returns the first element child or NULL if not available
+ * Note that entity references are not expanded.
+ *
+ * Returns the first element or NULL if parent has no children.
*/
xmlNodePtr
xmlFirstElementChild(xmlNodePtr parent) {
@@ -3500,10 +3435,10 @@
return(NULL);
switch (parent->type) {
case XML_ELEMENT_NODE:
- case XML_ENTITY_NODE:
case XML_DOCUMENT_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_HTML_DOCUMENT_NODE:
+ case XML_ENTITY_DECL:
cur = parent->children;
break;
default:
@@ -3521,12 +3456,11 @@
* xmlLastElementChild:
* @parent: the parent node
*
- * Finds the last child node of that element which is a Element node
- * Note the handling of entities references is different than in
- * the W3C DOM element traversal spec since we don't have back reference
- * from entities content to entities references.
+ * Find the last child node which is an element.
*
- * Returns the last element child or NULL if not available
+ * Note that entity references are not expanded.
+ *
+ * Returns the last element or NULL if parent has no children.
*/
xmlNodePtr
xmlLastElementChild(xmlNodePtr parent) {
@@ -3536,10 +3470,10 @@
return(NULL);
switch (parent->type) {
case XML_ELEMENT_NODE:
- case XML_ENTITY_NODE:
case XML_DOCUMENT_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_HTML_DOCUMENT_NODE:
+ case XML_ENTITY_DECL:
cur = parent->last;
break;
default:
@@ -3557,13 +3491,11 @@
* xmlPreviousElementSibling:
* @node: the current node
*
- * Finds the first closest previous sibling of the node which is an
- * element node.
- * Note the handling of entities references is different than in
- * the W3C DOM element traversal spec since we don't have back reference
- * from entities content to entities references.
+ * Find the closest preceding sibling which is a element.
*
- * Returns the previous element sibling or NULL if not available
+ * Note that entity references are not expanded.
+ *
+ * Returns the sibling or NULL if no sibling was found.
*/
xmlNodePtr
xmlPreviousElementSibling(xmlNodePtr node) {
@@ -3574,7 +3506,6 @@
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_XINCLUDE_START:
@@ -3596,13 +3527,11 @@
* xmlNextElementSibling:
* @node: the current node
*
- * Finds the first closest next sibling of the node which is an
- * element node.
- * Note the handling of entities references is different than in
- * the W3C DOM element traversal spec since we don't have back reference
- * from entities content to entities references.
+ * Find the closest following sibling which is a element.
*
- * Returns the next element sibling or NULL if not available
+ * Note that entity references are not expanded.
+ *
+ * Returns the sibling or NULL if no sibling was found.
*/
xmlNodePtr
xmlNextElementSibling(xmlNodePtr node) {
@@ -3613,7 +3542,6 @@
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_DTD_NODE:
@@ -3638,8 +3566,7 @@
* xmlFreeNodeList:
* @cur: the first node in the list
*
- * Free a node and all its siblings, this is a recursive behaviour, all
- * the children are freed too.
+ * Free a node list including all children.
*/
void
xmlFreeNodeList(xmlNodePtr cur) {
@@ -3669,8 +3596,14 @@
if ((cur->type == XML_DOCUMENT_NODE) ||
(cur->type == XML_HTML_DOCUMENT_NODE)) {
xmlFreeDoc((xmlDocPtr) cur);
- } else if (cur->type != XML_DTD_NODE) {
-
+ } else if (cur->type == XML_DTD_NODE) {
+ /*
+ * TODO: We should consider freeing the DTD if it isn't
+ * referenced from doc->intSubset or doc->extSubset.
+ */
+ cur->prev = NULL;
+ cur->next = NULL;
+ } else {
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
xmlDeregisterNodeDefaultValue(cur);
@@ -3721,8 +3654,10 @@
* xmlFreeNode:
* @cur: the node
*
- * Free a node, this is a recursive behaviour, all the children are freed too.
- * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
+ * Free a node including all the children.
+ *
+ * This doesn't unlink the node from the tree. Call xmlUnlinkNode first
+ * unless @cur is a root node.
*/
void
xmlFreeNode(xmlNodePtr cur) {
@@ -3788,11 +3723,10 @@
* xmlUnlinkNode:
* @cur: the node
*
- * Unlink a node from it's current context, the node is not freed
- * If one need to free the node, use xmlFreeNode() routine after the
- * unlink to discard it.
- * Note that namespace nodes can't be unlinked as they do not have
- * pointer to their parent.
+ * Unlink a node from its tree.
+ *
+ * The node is not freed. Unless it is reinserted, it must be managed
+ * manually and freed eventually by calling xmlFreeNode.
*/
void
xmlUnlinkNode(xmlNodePtr cur) {
@@ -3858,15 +3792,20 @@
/**
* xmlReplaceNode:
* @old: the old node
- * @cur: the node
+ * @cur: the node (optional)
*
- * Unlink the old node from its current context, prune the new one
- * at the same place. If @cur was already inserted in a document it is
- * first unlinked from its existing context.
+ * Unlink the old node. If @cur is provided, it is unlinked and
+ * inserted in place of @old.
*
- * See the note regarding namespaces in xmlAddChild.
+ * It is an error if @old has no parent.
*
- * Returns the @old node
+ * Unlike xmlAddChild, this function doesn't merge text nodes or
+ * delete duplicate attributes.
+ *
+ * See the notes in xmlAddChild.
+ *
+ * Returns @old or NULL if arguments are invalid or a memory
+ * allocation failed.
*/
xmlNodePtr
xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
@@ -3889,7 +3828,8 @@
return(old);
}
xmlUnlinkNode(cur);
- xmlSetTreeDoc(cur, old->doc);
+ if (xmlSetTreeDoc(cur, old->doc) < 0)
+ return(NULL);
cur->parent = old->parent;
cur->next = old->next;
if (cur->next != NULL)
@@ -3924,9 +3864,10 @@
* xmlCopyNamespace:
* @cur: the namespace
*
- * Do a copy of the namespace.
+ * Copy a namespace.
*
- * Returns: a new #xmlNsPtr, or NULL in case of error.
+ * Returns the copied namespace or NULL if a memory allocation
+ * failed.
*/
xmlNsPtr
xmlCopyNamespace(xmlNsPtr cur) {
@@ -3947,9 +3888,10 @@
* xmlCopyNamespaceList:
* @cur: the first namespace
*
- * Do a copy of an namespace list.
+ * Copy a namespace list.
*
- * Returns: a new #xmlNsPtr, or NULL in case of error.
+ * Returns the head of the copied list or NULL if a memory
+ * allocation failed.
*/
xmlNsPtr
xmlCopyNamespaceList(xmlNsPtr cur) {
@@ -3995,15 +3937,20 @@
if ((cur->ns != NULL) && (target != NULL)) {
xmlNsPtr ns;
+ int res;
- ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
+ res = xmlSearchNsSafe(target, cur->ns->prefix, &ns);
+ if (res < 0)
+ goto error;
if (ns == NULL) {
/*
* Humm, we are copying an element whose namespace is defined
* out of the new tree scope. Search it in the original tree
* and add it at the top of the new tree
*/
- ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
+ res = xmlSearchNsSafe(cur->parent, cur->ns->prefix, &ns);
+ if (res < 0)
+ goto error;
if (ns != NULL) {
xmlNodePtr root = target;
xmlNodePtr pred = NULL;
@@ -4034,7 +3981,7 @@
* we are in trouble: we need a new reconciled namespace.
* This is expensive
*/
- ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns);
+ ret->ns = xmlNewReconciledNs(target, cur->ns);
if (ret->ns == NULL)
goto error;
}
@@ -4073,10 +4020,10 @@
if (res != 0) {
xmlChar *id;
- id = xmlNodeListGetString(cur->doc, cur->children, 1);
+ id = xmlNodeGetContent((xmlNodePtr) cur);
if (id == NULL)
goto error;
- res = xmlAddIDSafe(target->doc, id, ret, 0, NULL);
+ res = xmlAddIDSafe(ret, id);
xmlFree(id);
if (res < 0)
goto error;
@@ -4094,9 +4041,14 @@
* @target: the element where the attribute will be grafted
* @cur: the attribute
*
- * Do a copy of the attribute.
+ * Create a copy of the attribute. This function sets the parent
+ * pointer of the copy to @target but doesn't set the attribute on
+ * the target element. Users should consider to set the attribute
+ * by calling xmlAddChild afterwards or reset the parent pointer to
+ * NULL.
*
- * Returns: a new #xmlAttrPtr, or NULL in case of error.
+ * Returns the copied attribute or NULL if a memory allocation
+ * failed.
*/
xmlAttrPtr
xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
@@ -4108,9 +4060,12 @@
* @target: the element where the attributes will be grafted
* @cur: the first attribute
*
- * Do a copy of an attribute list.
+ * Create a copy of an attribute list. This function sets the
+ * parent pointers of the copied attributes to @target but doesn't
+ * set the attributes on the target element.
*
- * Returns: a new #xmlAttrPtr, or NULL in case of error.
+ * Returns the head of the copied list or NULL if a memory
+ * allocation failed.
*/
xmlAttrPtr
xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
@@ -4168,7 +4123,6 @@
case XML_ELEMENT_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_XINCLUDE_START:
@@ -4184,12 +4138,7 @@
#ifdef LIBXML_TREE_ENABLED
return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
#endif /* LIBXML_TREE_ENABLED */
- case XML_DOCUMENT_TYPE_NODE:
- case XML_NOTATION_NODE:
- case XML_DTD_NODE:
- case XML_ELEMENT_DECL:
- case XML_ATTRIBUTE_DECL:
- case XML_ENTITY_DECL:
+ default:
return(NULL);
}
@@ -4251,6 +4200,8 @@
*/
tmp = xmlAddChild(parent, ret);
/* node could have coalesced */
+ if (tmp == NULL)
+ goto error;
if (tmp != ret)
return(tmp);
}
@@ -4265,9 +4216,12 @@
}
if ((node->type == XML_ELEMENT_NODE) && (node->ns != NULL)) {
- xmlNsPtr ns;
+ xmlNsPtr ns = NULL;
+ int res;
- ns = xmlSearchNs(doc, ret, node->ns->prefix);
+ res = xmlSearchNsSafe(ret, node->ns->prefix, &ns);
+ if (res < 0)
+ goto error;
if (ns == NULL) {
/*
* Humm, we are copying an element whose namespace is defined
@@ -4277,14 +4231,16 @@
* TODO: Searching the original tree seems unnecessary. We
* already have a namespace URI.
*/
- ns = xmlSearchNs(node->doc, node, node->ns->prefix);
+ res = xmlSearchNsSafe(node, node->ns->prefix, &ns);
+ if (res < 0)
+ goto error;
if (ns != NULL) {
xmlNodePtr root = ret;
while (root->parent != NULL) root = root->parent;
ret->ns = xmlNewNs(root, ns->href, ns->prefix);
} else {
- ret->ns = xmlNewReconciledNs(doc, ret, node->ns);
+ ret->ns = xmlNewReconciledNs(ret, node->ns);
}
if (ret->ns == NULL)
goto error;
@@ -4369,6 +4325,18 @@
return(NULL);
}
+/**
+ * xmlStaticCopyNodeList:
+ * @node: node to copy
+ * @doc: target document
+ * @parent: target node (optional)
+ *
+ * Copy a node list. If @parent is provided, sets the parent pointer
+ * of the copied nodes, but doesn't update the children and last
+ * pointer of @parent.
+ *
+ * Returns a the copy or NULL in case of error.
+ */
xmlNodePtr
xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
xmlNodePtr ret = NULL;
@@ -4377,23 +4345,44 @@
int linkedSubset = 0;
while (node != NULL) {
+ xmlNodePtr next = node->next;
+
#ifdef LIBXML_TREE_ENABLED
if (node->type == XML_DTD_NODE ) {
if (doc == NULL) {
- node = node->next;
+ node = next;
continue;
}
if ((doc->intSubset == NULL) && (newSubset == NULL)) {
q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
if (q == NULL) goto error;
- q->doc = doc;
+ /* Can't fail on DTD */
+ xmlSetTreeDoc(q, doc);
q->parent = parent;
newSubset = (xmlDtdPtr) q;
- xmlAddChild(parent, q);
} else {
+ /*
+ * We don't allow multiple internal subsets in a document,
+ * so we move the DTD instead of creating a copy.
+ */
linkedSubset = 1;
q = (xmlNodePtr) doc->intSubset;
- xmlAddChild(parent, q);
+ /* Unlink */
+ if (q->prev == NULL) {
+ if (q->parent != NULL)
+ q->parent->children = q->next;
+ } else {
+ q->prev->next = q->next;
+ }
+ if (q->next == NULL) {
+ if (q->parent != NULL)
+ q->parent->last = q->prev;
+ } else {
+ q->next->prev = q->prev;
+ }
+ q->parent = parent;
+ q->next = NULL;
+ q->prev = NULL;
}
} else
#endif /* LIBXML_TREE_ENABLED */
@@ -4408,13 +4397,15 @@
q->prev = p;
p = q;
}
- node = node->next;
+ node = next;
}
if ((doc != NULL) && (newSubset != NULL))
doc->intSubset = newSubset;
return(ret);
error:
xmlFreeNodeList(ret);
+ if (newSubset != NULL)
+ xmlFreeDtd(newSubset);
if (linkedSubset != 0) {
doc->intSubset->next = NULL;
doc->intSubset->prev = NULL;
@@ -4429,9 +4420,11 @@
* when applicable)
* if 2 copy properties and namespaces (when applicable)
*
- * Do a copy of the node.
+ * Copy a node.
*
- * Returns: a new #xmlNodePtr, or NULL in case of error.
+ * Use of this function is DISCOURAGED in favor of xmlDocCopyNode.
+ *
+ * Returns the copied node or NULL if a memory allocation failed.
*/
xmlNodePtr
xmlCopyNode(xmlNodePtr node, int extended) {
@@ -4449,9 +4442,9 @@
* when applicable)
* if 2 copy properties and namespaces (when applicable)
*
- * Do a copy of the node to a given document.
+ * Copy a node into another document.
*
- * Returns: a new #xmlNodePtr, or NULL in case of error.
+ * Returns the copied node or NULL if a memory allocation failed.
*/
xmlNodePtr
xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) {
@@ -4466,9 +4459,10 @@
* @doc: the target document
* @node: the first node in the list.
*
- * Do a recursive copy of the node list.
+ * Copy a node list and all children into a new document.
*
- * Returns: a new #xmlNodePtr, or NULL in case of error.
+ * Returns the head of the copied list or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) {
xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
@@ -4479,10 +4473,12 @@
* xmlCopyNodeList:
* @node: the first node in the list.
*
- * Do a recursive copy of the node list.
- * Use xmlDocCopyNodeList() if possible to ensure string interning.
+ * Copy a node list and all children.
*
- * Returns: a new #xmlNodePtr, or NULL in case of error.
+ * Use of this function is DISCOURAGED in favor of xmlDocCopyNodeList.
+ *
+ * Returns the head of the copied list or NULL if a memory
+ * allocation failed.
*/
xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
@@ -4492,11 +4488,11 @@
#if defined(LIBXML_TREE_ENABLED)
/**
* xmlCopyDtd:
- * @dtd: the dtd
+ * @dtd: the DTD
*
- * Do a copy of the dtd.
+ * Copy a DTD.
*
- * Returns: a new #xmlDtdPtr, or NULL in case of error.
+ * Returns the copied DTD or NULL if a memory allocation failed.
*/
xmlDtdPtr
xmlCopyDtd(xmlDtdPtr dtd) {
@@ -4603,10 +4599,11 @@
* @doc: the document
* @recursive: if not zero do a recursive copy.
*
- * Do a copy of the document info. If recursive, the content tree will
+ * Copy a document. If recursive, the content tree will
* be copied too as well as DTD, namespaces and entities.
*
- * Returns: a new #xmlDocPtr, or NULL in case of error.
+ * Returns the copied document or NULL if a memory allocation
+ * failed.
*/
xmlDocPtr
xmlCopyDoc(xmlDocPtr doc, int recursive) {
@@ -4643,8 +4640,8 @@
ret->intSubset = xmlCopyDtd(doc->intSubset);
if (ret->intSubset == NULL)
goto error;
+ /* Can't fail on DTD */
xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
- ret->intSubset->parent = ret;
}
#endif
if (doc->oldNs != NULL) {
@@ -4998,7 +4995,7 @@
* Get the root element of the document (doc->children is a list
* containing possibly comments, PIs, etc ...).
*
- * Returns the #xmlNodePtr for the root or NULL
+ * Returns the root element or NULL if no element was found.
*/
xmlNodePtr
xmlDocGetRootElement(const xmlDoc *doc) {
@@ -5024,24 +5021,30 @@
* Set the root element of the document (doc->children is a list
* containing possibly comments, PIs, etc ...).
*
- * Returns the old root element if any was found, NULL if root was NULL
+ * @root must be an element node. It is unlinked before insertion.
+ *
+ * Returns the unlinked old root element or NULL if the document
+ * didn't have a root element or a memory allocation failed.
*/
xmlNodePtr
xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
xmlNodePtr old = NULL;
if (doc == NULL) return(NULL);
- if ((root == NULL) || (root->type == XML_NAMESPACE_DECL))
+ if ((root == NULL) || (root->type != XML_ELEMENT_NODE))
return(NULL);
- xmlUnlinkNode(root);
- xmlSetTreeDoc(root, doc);
- root->parent = (xmlNodePtr) doc;
old = doc->children;
while (old != NULL) {
if (old->type == XML_ELEMENT_NODE)
break;
old = old->next;
}
+ if (old == root)
+ return(old);
+ xmlUnlinkNode(root);
+ if (xmlSetTreeDoc(root, doc) < 0)
+ return(NULL);
+ root->parent = (xmlNodePtr) doc;
if (old == NULL) {
if (doc->children == NULL) {
doc->children = root;
@@ -5064,40 +5067,27 @@
*
* Set the language of a node, i.e. the values of the xml:lang
* attribute.
+ *
+ * Return 0 on success, 1 if arguments are invalid, -1 if a
+ * memory allocation failed.
*/
-void
+int
xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
xmlNsPtr ns;
+ xmlAttrPtr attr;
+ int res;
- if (cur == NULL) return;
- switch(cur->type) {
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- case XML_COMMENT_NODE:
- case XML_DOCUMENT_NODE:
- case XML_DOCUMENT_TYPE_NODE:
- case XML_DOCUMENT_FRAG_NODE:
- case XML_NOTATION_NODE:
- case XML_HTML_DOCUMENT_NODE:
- case XML_DTD_NODE:
- case XML_ELEMENT_DECL:
- case XML_ATTRIBUTE_DECL:
- case XML_ENTITY_DECL:
- case XML_PI_NODE:
- case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
- case XML_NAMESPACE_DECL:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- return;
- case XML_ELEMENT_NODE:
- case XML_ATTRIBUTE_NODE:
- break;
- }
- ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
- if (ns == NULL)
- return;
- xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
+ if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
+ return(1);
+
+ res = xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns);
+ if (res != 0)
+ return(res);
+ attr = xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
+ if (attr == NULL)
+ return(-1);
+
+ return(0);
}
#endif /* LIBXML_TREE_ENABLED */
@@ -5114,15 +5104,22 @@
xmlChar *
xmlNodeGetLang(const xmlNode *cur) {
xmlChar *lang;
+ int res;
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
return(NULL);
+
while (cur != NULL) {
- lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
+ res = xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
+ &lang);
+ if (res < 0)
+ return(NULL);
if (lang != NULL)
return(lang);
+
cur = cur->parent;
}
+
return(NULL);
}
@@ -5135,47 +5132,34 @@
*
* Set (or reset) the space preserving behaviour of a node, i.e. the
* value of the xml:space attribute.
+ *
+ * Return 0 on success, 1 if arguments are invalid, -1 if a
+ * memory allocation failed.
*/
-void
+int
xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
xmlNsPtr ns;
+ xmlAttrPtr attr;
+ const char *string;
+ int res;
- if (cur == NULL) return;
- switch(cur->type) {
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- case XML_COMMENT_NODE:
- case XML_DOCUMENT_NODE:
- case XML_DOCUMENT_TYPE_NODE:
- case XML_DOCUMENT_FRAG_NODE:
- case XML_NOTATION_NODE:
- case XML_HTML_DOCUMENT_NODE:
- case XML_DTD_NODE:
- case XML_ELEMENT_DECL:
- case XML_ATTRIBUTE_DECL:
- case XML_ENTITY_DECL:
- case XML_PI_NODE:
- case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
- case XML_NAMESPACE_DECL:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- return;
- case XML_ELEMENT_NODE:
- case XML_ATTRIBUTE_NODE:
- break;
- }
- ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
- if (ns == NULL)
- return;
- switch (val) {
- case 0:
- xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
- break;
- case 1:
- xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
- break;
- }
+ if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
+ return(1);
+
+ res = xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns);
+ if (res != 0)
+ return(res);
+
+ if (val == 0)
+ string = "default";
+ else
+ string = "preserve";
+
+ attr = xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST string);
+ if (attr == NULL)
+ return(-1);
+
+ return(0);
}
#endif /* LIBXML_TREE_ENABLED */
@@ -5192,11 +5176,16 @@
int
xmlNodeGetSpacePreserve(const xmlNode *cur) {
xmlChar *space;
+ int res;
if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
return(-1);
+
while (cur != NULL) {
- space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
+ res = xmlNodeGetAttrValue(cur, BAD_CAST "space", XML_XML_NAMESPACE,
+ &space);
+ if (res < 0)
+ return(-1);
if (space != NULL) {
if (xmlStrEqual(space, BAD_CAST "preserve")) {
xmlFree(space);
@@ -5208,8 +5197,10 @@
}
xmlFree(space);
}
+
cur = cur->parent;
}
+
return(-1);
}
@@ -5225,52 +5216,39 @@
xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
xmlDocPtr doc;
xmlDictPtr dict;
- const xmlChar *freeme = NULL;
+ const xmlChar *copy;
+ const xmlChar *oldName;
if (cur == NULL) return;
if (name == NULL) return;
switch(cur->type) {
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- case XML_COMMENT_NODE:
- case XML_DOCUMENT_TYPE_NODE:
- case XML_DOCUMENT_FRAG_NODE:
- case XML_NOTATION_NODE:
- case XML_HTML_DOCUMENT_NODE:
- case XML_NAMESPACE_DECL:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- return;
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
case XML_PI_NODE:
case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
- case XML_DTD_NODE:
- case XML_DOCUMENT_NODE:
- case XML_ELEMENT_DECL:
- case XML_ATTRIBUTE_DECL:
- case XML_ENTITY_DECL:
break;
+ default:
+ return;
}
+
doc = cur->doc;
if (doc != NULL)
dict = doc->dict;
else
dict = NULL;
- /* TODO: malloc check */
- if (dict != NULL) {
- if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
- freeme = cur->name;
- cur->name = xmlDictLookup(dict, name, -1);
- } else {
- if (cur->name != NULL)
- freeme = cur->name;
- cur->name = xmlStrdup(name);
- }
- if (freeme)
- xmlFree((xmlChar *) freeme);
+ if (dict != NULL)
+ copy = xmlDictLookup(dict, name, -1);
+ else
+ copy = xmlStrdup(name);
+ if (copy == NULL)
+ return;
+
+ oldName = cur->name;
+ cur->name = copy;
+ if ((oldName != NULL) &&
+ ((dict == NULL) || (!xmlDictOwns(dict, oldName))))
+ xmlFree((xmlChar *) oldName);
}
#endif
@@ -5293,23 +5271,6 @@
if (cur == NULL)
return(-1);
switch(cur->type) {
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- case XML_COMMENT_NODE:
- case XML_DOCUMENT_TYPE_NODE:
- case XML_DOCUMENT_FRAG_NODE:
- case XML_NOTATION_NODE:
- case XML_DTD_NODE:
- case XML_ELEMENT_DECL:
- case XML_ATTRIBUTE_DECL:
- case XML_ENTITY_DECL:
- case XML_PI_NODE:
- case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
- case XML_NAMESPACE_DECL:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- return(-1);
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
break;
@@ -5328,9 +5289,11 @@
}
return(0);
}
+ default:
+ return(-1);
}
- ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
+ xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns);
if (ns == NULL)
return(-1);
fixed = xmlPathToURI(uri);
@@ -5411,6 +5374,8 @@
if (cur->type == XML_ENTITY_DECL) {
xmlEntityPtr ent = (xmlEntityPtr) cur;
+ if (ent->URI == NULL)
+ break;
xmlFree(ret);
ret = xmlStrdup(ent->URI);
if (ret == NULL)
@@ -5509,6 +5474,59 @@
return(0);
}
+static void
+xmlBufGetEntityRefContent(xmlBufPtr buf, const xmlNode *ref) {
+ xmlEntityPtr ent;
+
+ if (ref->children != NULL) {
+ ent = (xmlEntityPtr) ref->children;
+ } else {
+ /* lookup entity declaration */
+ ent = xmlGetDocEntity(ref->doc, ref->name);
+ if (ent == NULL)
+ return;
+ }
+
+ if (ent->flags & XML_ENT_EXPANDING)
+ return;
+
+ ent->flags |= XML_ENT_EXPANDING;
+ xmlBufGetChildContent(buf, (xmlNodePtr) ent);
+ ent->flags &= ~XML_ENT_EXPANDING;
+}
+
+static void
+xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree) {
+ const xmlNode *cur = tree->children;
+
+ while (cur != NULL) {
+ switch (cur->type) {
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ xmlBufCat(buf, cur->content);
+ break;
+
+ case XML_ENTITY_REF_NODE:
+ xmlBufGetEntityRefContent(buf, cur);
+ break;
+
+ default:
+ if (cur->children != NULL) {
+ cur = cur->children;
+ continue;
+ }
+ break;
+ }
+
+ while (cur->next == NULL) {
+ cur = cur->parent;
+ if (cur == tree)
+ return;
+ }
+ cur = cur->next;
+ }
+}
+
/**
* xmlBufGetNodeContent:
* @buf: a buffer xmlBufPtr
@@ -5525,127 +5543,38 @@
int
xmlBufGetNodeContent(xmlBufPtr buf, const xmlNode *cur)
{
- if ((cur == NULL) || (buf == NULL)) return(-1);
+ if ((cur == NULL) || (buf == NULL))
+ return(-1);
+
switch (cur->type) {
+ case XML_DOCUMENT_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+ case XML_DOCUMENT_FRAG_NODE:
+ case XML_ELEMENT_NODE:
+ case XML_ATTRIBUTE_NODE:
+ case XML_ENTITY_DECL:
+ xmlBufGetChildContent(buf, cur);
+ break;
+
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
- xmlBufCat(buf, cur->content);
- break;
- case XML_DOCUMENT_FRAG_NODE:
- case XML_ELEMENT_NODE:{
- const xmlNode *tmp = cur;
-
- while (tmp != NULL) {
- switch (tmp->type) {
- case XML_CDATA_SECTION_NODE:
- case XML_TEXT_NODE:
- if (tmp->content != NULL)
- xmlBufCat(buf, tmp->content);
- break;
- case XML_ENTITY_REF_NODE:
- xmlBufGetNodeContent(buf, tmp);
- break;
- default:
- break;
- }
- /*
- * Skip to next node
- */
- if (tmp->children != NULL) {
- if (tmp->children->type != XML_ENTITY_DECL) {
- tmp = tmp->children;
- continue;
- }
- }
- if (tmp == cur)
- break;
-
- if (tmp->next != NULL) {
- tmp = tmp->next;
- continue;
- }
-
- do {
- tmp = tmp->parent;
- if (tmp == NULL)
- break;
- if (tmp == cur) {
- tmp = NULL;
- break;
- }
- if (tmp->next != NULL) {
- tmp = tmp->next;
- break;
- }
- } while (tmp != NULL);
- }
- break;
- }
- case XML_ATTRIBUTE_NODE:{
- xmlAttrPtr attr = (xmlAttrPtr) cur;
- xmlNodePtr tmp = attr->children;
-
- while (tmp != NULL) {
- if (tmp->type == XML_TEXT_NODE)
- xmlBufCat(buf, tmp->content);
- else
- xmlBufGetNodeContent(buf, tmp);
- tmp = tmp->next;
- }
- break;
- }
case XML_COMMENT_NODE:
case XML_PI_NODE:
xmlBufCat(buf, cur->content);
break;
- case XML_ENTITY_REF_NODE:{
- xmlEntityPtr ent;
- xmlNodePtr tmp;
- /* lookup entity declaration */
- ent = xmlGetDocEntity(cur->doc, cur->name);
- if (ent == NULL)
- return(-1);
-
- /* an entity content can be any "well balanced chunk",
- * i.e. the result of the content [43] production:
- * http://www.w3.org/TR/REC-xml#NT-content
- * -> we iterate through child nodes and recursive call
- * xmlNodeGetContent() which handles all possible node types */
- tmp = ent->children;
- while (tmp) {
- xmlBufGetNodeContent(buf, tmp);
- tmp = tmp->next;
- }
- break;
- }
- case XML_ENTITY_NODE:
- case XML_DOCUMENT_TYPE_NODE:
- case XML_NOTATION_NODE:
- case XML_DTD_NODE:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
+ case XML_ENTITY_REF_NODE:
+ xmlBufGetEntityRefContent(buf, cur);
break;
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
- cur = cur->children;
- while (cur!= NULL) {
- if ((cur->type == XML_ELEMENT_NODE) ||
- (cur->type == XML_TEXT_NODE) ||
- (cur->type == XML_CDATA_SECTION_NODE)) {
- xmlBufGetNodeContent(buf, cur);
- }
- cur = cur->next;
- }
- break;
+
case XML_NAMESPACE_DECL:
xmlBufCat(buf, ((xmlNsPtr) cur)->href);
break;
- case XML_ELEMENT_DECL:
- case XML_ATTRIBUTE_DECL:
- case XML_ENTITY_DECL:
+
+ default:
break;
}
+
return(0);
}
@@ -5663,98 +5592,103 @@
xmlChar *
xmlNodeGetContent(const xmlNode *cur)
{
+ xmlBufPtr buf;
+ xmlChar *ret;
+
if (cur == NULL)
return (NULL);
- switch (cur->type) {
- case XML_DOCUMENT_FRAG_NODE:
- case XML_ELEMENT_NODE:{
- xmlBufPtr buf;
- xmlChar *ret;
- buf = xmlBufCreateSize(64);
- if (buf == NULL)
- return (NULL);
- xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
- xmlBufGetNodeContent(buf, cur);
- ret = xmlBufDetach(buf);
- xmlBufFree(buf);
- return (ret);
- }
+ switch (cur->type) {
+ case XML_DOCUMENT_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+ case XML_ENTITY_REF_NODE:
+ break;
+
+ case XML_DOCUMENT_FRAG_NODE:
+ case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
- return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur));
+ case XML_ENTITY_DECL: {
+ xmlNodePtr children = cur->children;
+
+ if (children == NULL)
+ return(xmlStrdup(BAD_CAST ""));
+
+ /* Optimization for single text children */
+ if (((children->type == XML_TEXT_NODE) ||
+ (children->type == XML_CDATA_SECTION_NODE)) &&
+ (children->next == NULL)) {
+ if (children->content == NULL)
+ return(xmlStrdup(BAD_CAST ""));
+ return(xmlStrdup(children->content));
+ }
+
+ break;
+ }
+
+ case XML_CDATA_SECTION_NODE:
+ case XML_TEXT_NODE:
case XML_COMMENT_NODE:
case XML_PI_NODE:
if (cur->content != NULL)
- return (xmlStrdup(cur->content));
+ return(xmlStrdup(cur->content));
else
- return (xmlStrdup(BAD_CAST ""));
- return (NULL);
- case XML_ENTITY_REF_NODE:{
- xmlEntityPtr ent;
- xmlBufPtr buf;
- xmlChar *ret;
+ return(xmlStrdup(BAD_CAST ""));
- /* lookup entity declaration */
- ent = xmlGetDocEntity(cur->doc, cur->name);
- if (ent == NULL)
- return (NULL);
+ case XML_NAMESPACE_DECL:
+ return(xmlStrdup(((xmlNsPtr) cur)->href));
- buf = xmlBufCreate();
- if (buf == NULL)
- return (NULL);
- xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
-
- xmlBufGetNodeContent(buf, cur);
-
- ret = xmlBufDetach(buf);
- xmlBufFree(buf);
- return (ret);
- }
- case XML_ENTITY_NODE:
- case XML_DOCUMENT_TYPE_NODE:
- case XML_NOTATION_NODE:
- case XML_DTD_NODE:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- return (NULL);
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE: {
- xmlBufPtr buf;
- xmlChar *ret;
-
- buf = xmlBufCreate();
- if (buf == NULL)
- return (NULL);
- xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
-
- xmlBufGetNodeContent(buf, (xmlNodePtr) cur);
-
- ret = xmlBufDetach(buf);
- xmlBufFree(buf);
- return (ret);
- }
- case XML_NAMESPACE_DECL: {
- xmlChar *tmp;
-
- tmp = xmlStrdup(((xmlNsPtr) cur)->href);
- return (tmp);
- }
- case XML_ELEMENT_DECL:
- /* TODO !!! */
- return (NULL);
- case XML_ATTRIBUTE_DECL:
- /* TODO !!! */
- return (NULL);
- case XML_ENTITY_DECL:
- /* TODO !!! */
- return (NULL);
- case XML_CDATA_SECTION_NODE:
- case XML_TEXT_NODE:
- if (cur->content != NULL)
- return (xmlStrdup(cur->content));
- return (NULL);
+ default:
+ return(NULL);
}
- return (NULL);
+
+ buf = xmlBufCreateSize(64);
+ if (buf == NULL)
+ return (NULL);
+ xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
+ xmlBufGetNodeContent(buf, cur);
+ ret = xmlBufDetach(buf);
+ xmlBufFree(buf);
+
+ return(ret);
+}
+
+static int
+xmlNodeSetContentInternal(xmlNodePtr cur, const xmlChar *content, int len) {
+ if (cur == NULL) {
+ return(1);
+ }
+ switch (cur->type) {
+ case XML_DOCUMENT_FRAG_NODE:
+ case XML_ELEMENT_NODE:
+ case XML_ATTRIBUTE_NODE:
+ if (xmlNodeParseContent(cur, content, len) < 0)
+ return(-1);
+ break;
+
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ case XML_PI_NODE:
+ case XML_COMMENT_NODE: {
+ xmlChar *copy = NULL;
+
+ if (content != NULL) {
+ if (len < 0)
+ copy = xmlStrdup(content);
+ else
+ copy = xmlStrndup(content, len);
+ if (copy == NULL)
+ return(-1);
+ }
+
+ xmlTextSetContent(cur, copy);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return(0);
}
/**
@@ -5762,86 +5696,27 @@
* @cur: the node being modified
* @content: the new value of the content
*
- * Replace the content of a node.
- * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
- * references, but XML special chars need to be escaped first by using
- * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
+ * Replace the text content of a node.
+ *
+ * Sets the raw text content of text, CDATA, comment or PI nodes.
+ *
+ * For element and attribute nodes, removes all children and
+ * replaces them by parsing @content which is expected to be a
+ * valid XML attribute value possibly containing character and
+ * entity references. Syntax errors and references to undeclared
+ * entities are ignored silently. Unfortunately, there isn't an
+ * API to pass raw content directly. An inefficient work-around
+ * is to escape the content with xmlEncodeSpecialChars before
+ * passing it. A better trick is clearing the old content
+ * with xmlNodeSetContent(node, NULL) first and then calling
+ * xmlNodeAddContent(node, content). Unlike this function,
+ * xmlNodeAddContent accepts raw text.
*
* Returns 0 on success, 1 on error, -1 if a memory allocation failed.
*/
int
xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
- if (cur == NULL) {
- return(1);
- }
- switch (cur->type) {
- case XML_DOCUMENT_FRAG_NODE:
- case XML_ELEMENT_NODE:
- case XML_ATTRIBUTE_NODE: {
- xmlNodePtr list = NULL;
-
- if (content != NULL) {
- list = xmlStringGetNodeList(cur->doc, content);
- if (list == NULL)
- return(-1);
- }
-
- if (cur->children != NULL)
- xmlFreeNodeList(cur->children);
- cur->children = list;
- UPDATE_LAST_CHILD_AND_PARENT(cur)
- break;
- }
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
- case XML_PI_NODE:
- case XML_COMMENT_NODE: {
- xmlChar *copy = NULL;
-
- if (content != NULL) {
- copy = xmlStrdup(content);
- if (copy == NULL)
- return(-1);
- }
-
- if ((cur->content != NULL) &&
- (cur->content != (xmlChar *) &(cur->properties))) {
- if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
- (xmlDictOwns(cur->doc->dict, cur->content))))
- xmlFree(cur->content);
- }
- if (cur->children != NULL)
- xmlFreeNodeList(cur->children);
- cur->last = cur->children = NULL;
- cur->content = copy;
- break;
- }
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
- case XML_DOCUMENT_TYPE_NODE:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- break;
- case XML_NOTATION_NODE:
- break;
- case XML_DTD_NODE:
- break;
- case XML_NAMESPACE_DECL:
- break;
- case XML_ELEMENT_DECL:
- /* TODO !!! */
- break;
- case XML_ATTRIBUTE_DECL:
- /* TODO !!! */
- break;
- case XML_ENTITY_DECL:
- /* TODO !!! */
- break;
- }
-
- return(0);
+ return(xmlNodeSetContentInternal(cur, content, -1));
}
#ifdef LIBXML_TREE_ENABLED
@@ -5851,84 +5726,13 @@
* @content: the new value of the content
* @len: the size of @content
*
- * Replace the content of a node.
- * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
- * references, but XML special chars need to be escaped first by using
- * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
+ * See xmlNodeSetContent.
*
* Returns 0 on success, 1 on error, -1 if a memory allocation failed.
*/
int
xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
- if (cur == NULL) {
- return(1);
- }
- switch (cur->type) {
- case XML_DOCUMENT_FRAG_NODE:
- case XML_ELEMENT_NODE:
- case XML_ATTRIBUTE_NODE: {
- xmlNodePtr list = NULL;
-
- if (content != NULL) {
- list = xmlStringLenGetNodeList(cur->doc, content, len);
- if (list == NULL)
- return(-1);
- }
-
- if (cur->children != NULL)
- xmlFreeNodeList(cur->children);
- cur->children = list;
- UPDATE_LAST_CHILD_AND_PARENT(cur)
- break;
- }
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
- case XML_PI_NODE:
- case XML_COMMENT_NODE:
- case XML_NOTATION_NODE: {
- xmlChar *copy = NULL;
-
- if (content != NULL) {
- copy = xmlStrndup(content, len);
- if (copy == NULL)
- return(-1);
- }
-
- if ((cur->content != NULL) &&
- (cur->content != (xmlChar *) &(cur->properties))) {
- if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
- (xmlDictOwns(cur->doc->dict, cur->content))))
- xmlFree(cur->content);
- }
- if (cur->children != NULL)
- xmlFreeNodeList(cur->children);
- cur->children = cur->last = NULL;
- cur->content = copy;
- cur->properties = NULL;
- break;
- }
- case XML_DOCUMENT_NODE:
- case XML_DTD_NODE:
- case XML_HTML_DOCUMENT_NODE:
- case XML_DOCUMENT_TYPE_NODE:
- case XML_NAMESPACE_DECL:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- break;
- case XML_ELEMENT_DECL:
- /* TODO !!! */
- break;
- case XML_ATTRIBUTE_DECL:
- /* TODO !!! */
- break;
- case XML_ENTITY_DECL:
- /* TODO !!! */
- break;
- }
-
- return(0);
+ return(xmlNodeSetContentInternal(cur, content, len));
}
#endif /* LIBXML_TREE_ENABLED */
@@ -5961,49 +5765,21 @@
if (newNode == NULL)
return(-1);
tmp = xmlAddChild(cur, newNode);
- if (tmp == NULL)
+ if (tmp == NULL) {
+ xmlFreeNode(newNode);
return(-1);
+ }
break;
}
case XML_ATTRIBUTE_NODE:
break;
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
- case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
- case XML_NOTATION_NODE: {
- xmlChar *newContent = NULL;
-
- if ((cur->content == (xmlChar *) &(cur->properties)) ||
- ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
- xmlDictOwns(cur->doc->dict, cur->content))) {
- newContent = xmlStrncatNew(cur->content, content, len);
- if (newContent == NULL)
- return(-1);
- cur->properties = NULL;
- } else {
- newContent = xmlStrncatNew(cur->content, content, len);
- if (newContent == NULL)
- return(-1);
- xmlFree(cur->content);
- }
- cur->content = newContent;
- break;
- }
- case XML_DOCUMENT_NODE:
- case XML_DTD_NODE:
- case XML_HTML_DOCUMENT_NODE:
- case XML_DOCUMENT_TYPE_NODE:
- case XML_NAMESPACE_DECL:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- break;
- case XML_ELEMENT_DECL:
- case XML_ATTRIBUTE_DECL:
- case XML_ENTITY_DECL:
- break;
+ return(xmlTextAddContent(cur, content, len));
+ default:
+ break;
}
return(0);
@@ -6031,18 +5807,22 @@
* @first: the first text node
* @second: the second text node being merged
*
- * Merge two text nodes into one
- * Returns the first text node augmented
+ * Merge the second text node into the first. The second node is
+ * unlinked and freed.
+ *
+ * Returns the first text node augmented or NULL in case of error.
*/
xmlNodePtr
xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
- if (first == NULL) return(second);
- if (second == NULL) return(first);
- if (first->type != XML_TEXT_NODE) return(first);
- if (second->type != XML_TEXT_NODE) return(first);
- if (second->name != first->name)
- return(first);
- xmlNodeAddContent(first, second->content);
+ if ((first == NULL) || (first->type != XML_TEXT_NODE) ||
+ (second == NULL) || (second->type != XML_TEXT_NODE) ||
+ (first == second) ||
+ (first->name != second->name))
+ return(NULL);
+
+ if (xmlTextAddContent(first, second->content, -1) < 0)
+ return(NULL);
+
xmlUnlinkNode(second);
xmlFreeNode(second);
return(first);
@@ -6050,17 +5830,17 @@
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
/**
- * xmlGetNsList:
+ * xmlGetNsListSafe:
* @doc: the document
* @node: the current node
* @out: the returned namespace array
*
- * Search all the namespace applying to a given element. @out returns
- * a NULL terminated array of all the namespaces found that needs to be
- * freed by the caller allocation failed.
+ * Find all in-scope namespaces of a node. @out returns a NULL
+ * terminated array of namespace pointers that must be freed by
+ * the caller.
*
- * Returns 0 on success, 1 if no namespace were found, -1 if a memory
- * allocation failed.
+ * Returns 0 on success, 1 if no namespaces were found, -1 if a
+ * memory allocation failed.
*/
int
xmlGetNsListSafe(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node,
@@ -6120,10 +5900,13 @@
* @doc: the document
* @node: the current node
*
- * Search all the namespace applying to a given element.
- * Returns an NULL terminated array of all the #xmlNsPtr found
- * that need to be freed by the caller or NULL if a memory
- * allocation failed
+ * Find all in-scope namespaces of a node.
+ *
+ * Use xmlGetNsListSafe for better error reporting.
+ *
+ * Returns a NULL terminated array of namespace pointers that must
+ * be freed by the caller or NULL if no namespaces were found or
+ * a memory allocation failed.
*/
xmlNsPtr *
xmlGetNsList(const xmlDoc *doc, const xmlNode *node)
@@ -6135,6 +5918,29 @@
}
#endif /* LIBXML_TREE_ENABLED */
+static xmlNsPtr
+xmlNewXmlNs(void) {
+ xmlNsPtr ns;
+
+ ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
+ if (ns == NULL)
+ return(NULL);
+ memset(ns, 0, sizeof(xmlNs));
+ ns->type = XML_LOCAL_NAMESPACE;
+ ns->href = xmlStrdup(XML_XML_NAMESPACE);
+ if (ns->href == NULL) {
+ xmlFreeNs(ns);
+ return(NULL);
+ }
+ ns->prefix = xmlStrdup(BAD_CAST "xml");
+ if (ns->prefix == NULL) {
+ xmlFreeNs(ns);
+ return(NULL);
+ }
+
+ return(ns);
+}
+
/*
* xmlTreeEnsureXMLDecl:
* @doc: the doc
@@ -6143,33 +5949,89 @@
*
* Returns the XML ns-struct or NULL if a memory allocation failed.
*/
-xmlNsPtr
+static xmlNsPtr
xmlTreeEnsureXMLDecl(xmlDocPtr doc)
{
- if (doc == NULL)
- return (NULL);
- if (doc->oldNs != NULL)
- return (doc->oldNs);
- {
- xmlNsPtr ns;
- ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
- if (ns == NULL)
- return(NULL);
- memset(ns, 0, sizeof(xmlNs));
- ns->type = XML_LOCAL_NAMESPACE;
- ns->href = xmlStrdup(XML_XML_NAMESPACE);
- if (ns->href == NULL) {
- xmlFreeNs(ns);
- return(NULL);
- }
- ns->prefix = xmlStrdup((const xmlChar *)"xml");
- if (ns->prefix == NULL) {
- xmlFreeNs(ns);
- return(NULL);
- }
- doc->oldNs = ns;
+ xmlNsPtr ns;
+
+ ns = doc->oldNs;
+ if (ns != NULL)
return (ns);
+
+ ns = xmlNewXmlNs();
+ doc->oldNs = ns;
+
+ return(ns);
+}
+
+int
+xmlSearchNsSafe(xmlNodePtr node, const xmlChar *prefix,
+ xmlNsPtr *out) {
+ xmlNsPtr cur;
+ xmlDocPtr doc;
+ xmlNodePtr orig = node;
+ xmlNodePtr parent;
+
+ if (out == NULL)
+ return(1);
+ *out = NULL;
+ if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
+ return(1);
+
+ doc = node->doc;
+
+ if ((doc != NULL) && (IS_STR_XML(prefix))) {
+ cur = xmlTreeEnsureXMLDecl(doc);
+ if (cur == NULL)
+ return(-1);
+ *out = cur;
+ return(0);
}
+
+ while (node->type != XML_ELEMENT_NODE) {
+ node = node->parent;
+ if (node == NULL)
+ return(0);
+ }
+
+ parent = node;
+
+ while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
+ cur = node->nsDef;
+ while (cur != NULL) {
+ if (xmlStrEqual(cur->prefix, prefix)) {
+ *out = cur;
+ return(0);
+ }
+ cur = cur->next;
+ }
+ if (orig != node) {
+ cur = node->ns;
+ if ((cur != NULL) &&
+ (xmlStrEqual(cur->prefix, prefix))) {
+ *out = cur;
+ return(0);
+ }
+ }
+
+ node = node->parent;
+ }
+
+ /*
+ * The XML-1.0 namespace is normally held on the document
+ * element. In this case exceptionally create it on the
+ * node element.
+ */
+ if ((doc == NULL) && (IS_STR_XML(prefix))) {
+ cur = xmlNewXmlNs();
+ if (cur == NULL)
+ return(-1);
+ cur->next = parent->nsDef;
+ parent->nsDef = cur;
+ *out = cur;
+ }
+
+ return(0);
}
/**
@@ -6188,81 +6050,15 @@
*
* Returns the namespace pointer or NULL if no namespace was found or
* a memory allocation failed. Allocations can only fail if the "xml"
- * namespace is queried and xmlTreeEnsureXMLDecl wasn't called
- * successfully or doc is NULL.
+ * namespace is queried.
*/
xmlNsPtr
-xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
-
+xmlSearchNs(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
+ const xmlChar *nameSpace) {
xmlNsPtr cur;
- const xmlNode *orig = node;
- if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(NULL);
- if ((nameSpace != NULL) &&
- (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
- if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
- /*
- * The XML-1.0 namespace is normally held on the root
- * element. In this case exceptionally create it on the
- * node element.
- */
- cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
- if (cur == NULL)
- return(NULL);
- memset(cur, 0, sizeof(xmlNs));
- cur->type = XML_LOCAL_NAMESPACE;
- cur->href = xmlStrdup(XML_XML_NAMESPACE);
- cur->prefix = xmlStrdup((const xmlChar *)"xml");
- cur->next = node->nsDef;
- node->nsDef = cur;
- return(cur);
- }
- if (doc == NULL) {
- doc = node->doc;
- if (doc == NULL)
- return(NULL);
- }
- /*
- * Return the XML namespace declaration held by the doc.
- */
- if (doc->oldNs == NULL)
- return(xmlTreeEnsureXMLDecl(doc));
- else
- return(doc->oldNs);
- }
- while (node != NULL) {
- if ((node->type == XML_ENTITY_REF_NODE) ||
- (node->type == XML_ENTITY_NODE) ||
- (node->type == XML_ENTITY_DECL))
- return(NULL);
- if (node->type == XML_ELEMENT_NODE) {
- cur = node->nsDef;
- while (cur != NULL) {
- if ((cur->prefix == NULL) && (nameSpace == NULL) &&
- (cur->href != NULL))
- return(cur);
- if ((cur->prefix != NULL) && (nameSpace != NULL) &&
- (cur->href != NULL) &&
- (xmlStrEqual(cur->prefix, nameSpace)))
- return(cur);
- cur = cur->next;
- }
- if (orig != node) {
- cur = node->ns;
- if (cur != NULL) {
- if ((cur->prefix == NULL) && (nameSpace == NULL) &&
- (cur->href != NULL))
- return(cur);
- if ((cur->prefix != NULL) && (nameSpace != NULL) &&
- (cur->href != NULL) &&
- (xmlStrEqual(cur->prefix, nameSpace)))
- return(cur);
- }
- }
- }
- node = node->parent;
- }
- return(NULL);
+ xmlSearchNsSafe(node, nameSpace, &cur);
+ return(cur);
}
/**
@@ -6285,7 +6081,6 @@
while ((node != NULL) && (node != ancestor)) {
if ((node->type == XML_ENTITY_REF_NODE) ||
- (node->type == XML_ENTITY_NODE) ||
(node->type == XML_ENTITY_DECL))
return (-1);
if (node->type == XML_ELEMENT_NODE) {
@@ -6308,6 +6103,87 @@
return (1);
}
+int
+xmlSearchNsByHrefSafe(xmlNodePtr node, const xmlChar *href,
+ xmlNsPtr *out) {
+ xmlNsPtr cur;
+ xmlDocPtr doc;
+ xmlNodePtr orig = node;
+ xmlNodePtr parent;
+ int is_attr;
+
+ if (out == NULL)
+ return(1);
+ *out = NULL;
+ if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
+ return(1);
+
+ doc = node->doc;
+
+ if ((doc != NULL) && (xmlStrEqual(href, XML_XML_NAMESPACE))) {
+ cur = xmlTreeEnsureXMLDecl(doc);
+ if (cur == NULL)
+ return(-1);
+ *out = cur;
+ return(0);
+ }
+
+ is_attr = (node->type == XML_ATTRIBUTE_NODE);
+
+ while (node->type != XML_ELEMENT_NODE) {
+ node = node->parent;
+ if (node == NULL)
+ return(0);
+ }
+
+ parent = node;
+
+ while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
+ cur = node->nsDef;
+ while (cur != NULL) {
+ if (xmlStrEqual(cur->href, href)) {
+ if (((!is_attr) || (cur->prefix != NULL)) &&
+ (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) {
+ *out = cur;
+ return(0);
+ }
+ }
+ cur = cur->next;
+ }
+ if (orig != node) {
+ cur = node->ns;
+ if (cur != NULL) {
+ if (xmlStrEqual(cur->href, href)) {
+ if (((!is_attr) || (cur->prefix != NULL)) &&
+ (xmlNsInScope(doc, orig, node,
+ cur->prefix) == 1)) {
+ *out = cur;
+ return(0);
+ }
+ }
+ }
+ }
+
+ node = node->parent;
+ }
+
+ /*
+ * The XML-1.0 namespace is normally held on the document
+ * element. In this case exceptionally create it on the
+ * node element.
+ */
+ if ((doc == NULL) && (xmlStrEqual(href, XML_XML_NAMESPACE))) {
+ cur = xmlNewXmlNs();
+ if (cur == NULL)
+ return(-1);
+ cur->next = parent->nsDef;
+ parent->nsDef = cur;
+ *out = cur;
+ }
+
+ return(0);
+}
+
/**
* xmlSearchNsByHref:
* @doc: the document
@@ -6319,84 +6195,15 @@
*
* Returns the namespace pointer or NULL if no namespace was found or
* a memory allocation failed. Allocations can only fail if the "xml"
- * namespace is queried and xmlTreeEnsureXMLDecl wasn't called
- * successfully or doc is NULL.
+ * namespace is queried.
*/
xmlNsPtr
-xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
-{
+xmlSearchNsByHref(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
+ const xmlChar * href) {
xmlNsPtr cur;
- xmlNodePtr orig = node;
- int is_attr;
- if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (href == NULL))
- return (NULL);
- if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
- /*
- * Only the document can hold the XML spec namespace.
- */
- if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
- /*
- * The XML-1.0 namespace is normally held on the root
- * element. In this case exceptionally create it on the
- * node element.
- */
- cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
- if (cur == NULL)
- return (NULL);
- memset(cur, 0, sizeof(xmlNs));
- cur->type = XML_LOCAL_NAMESPACE;
- cur->href = xmlStrdup(XML_XML_NAMESPACE);
- cur->prefix = xmlStrdup((const xmlChar *) "xml");
- cur->next = node->nsDef;
- node->nsDef = cur;
- return (cur);
- }
- if (doc == NULL) {
- doc = node->doc;
- if (doc == NULL)
- return(NULL);
- }
- /*
- * Return the XML namespace declaration held by the doc.
- */
- if (doc->oldNs == NULL)
- return(xmlTreeEnsureXMLDecl(doc));
- else
- return(doc->oldNs);
- }
- is_attr = (node->type == XML_ATTRIBUTE_NODE);
- while (node != NULL) {
- if ((node->type == XML_ENTITY_REF_NODE) ||
- (node->type == XML_ENTITY_NODE) ||
- (node->type == XML_ENTITY_DECL))
- return (NULL);
- if (node->type == XML_ELEMENT_NODE) {
- cur = node->nsDef;
- while (cur != NULL) {
- if ((cur->href != NULL) && (href != NULL) &&
- (xmlStrEqual(cur->href, href))) {
- if (((!is_attr) || (cur->prefix != NULL)) &&
- (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
- return (cur);
- }
- cur = cur->next;
- }
- if (orig != node) {
- cur = node->ns;
- if (cur != NULL) {
- if ((cur->href != NULL) && (href != NULL) &&
- (xmlStrEqual(cur->href, href))) {
- if (((!is_attr) || (cur->prefix != NULL)) &&
- (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
- return (cur);
- }
- }
- }
- }
- node = node->parent;
- }
- return (NULL);
+ xmlSearchNsByHrefSafe(node, href, &cur);
+ return(cur);
}
/**
@@ -6413,10 +6220,11 @@
* Returns the (new) namespace definition or NULL in case of error
*/
static xmlNsPtr
-xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
+xmlNewReconciledNs(xmlNodePtr tree, xmlNsPtr ns) {
xmlNsPtr def;
xmlChar prefix[50];
int counter = 1;
+ int res;
if ((tree == NULL) || (tree->type != XML_ELEMENT_NODE)) {
return(NULL);
@@ -6427,7 +6235,9 @@
/*
* Search an existing namespace definition inherited.
*/
- def = xmlSearchNsByHref(doc, tree, ns->href);
+ res = xmlSearchNsByHrefSafe(tree, ns->href, &def);
+ if (res < 0)
+ return(NULL);
if (def != NULL)
return(def);
@@ -6440,7 +6250,9 @@
else
snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
- def = xmlSearchNs(doc, tree, prefix);
+ res = xmlSearchNsSafe(tree, prefix, &def);
+ if (res < 0)
+ return(NULL);
while (def != NULL) {
if (counter > 1000) return(NULL);
if (ns->prefix == NULL)
@@ -6448,7 +6260,9 @@
else
snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
(char *)ns->prefix, counter++);
- def = xmlSearchNs(doc, tree, prefix);
+ res = xmlSearchNsSafe(tree, prefix, &def);
+ if (res < 0)
+ return(NULL);
}
/*
@@ -6459,6 +6273,12 @@
}
#ifdef LIBXML_TREE_ENABLED
+
+typedef struct {
+ xmlNsPtr oldNs;
+ xmlNsPtr newNs;
+} xmlNsCache;
+
/**
* xmlReconciliateNs:
* @doc: the document
@@ -6471,12 +6291,12 @@
* as possible the function try to reuse the existing namespaces found in
* the new environment. If not possible the new namespaces are redeclared
* on @tree at the top of the given subtree.
- * Returns the number of namespace declarations created or -1 in case of error.
+ *
+ * Returns 0 on success or -1 in case of error.
*/
int
xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
- xmlNsPtr *oldNs = NULL;
- xmlNsPtr *newNs = NULL;
+ xmlNsCache *cache = NULL;
int sizeCache = 0;
int nbCache = 0;
@@ -6486,32 +6306,15 @@
int ret = 0, i;
if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
- if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
if (node->doc != doc) return(-1);
while (node != NULL) {
/*
* Reconciliate the node namespace
*/
if (node->ns != NULL) {
- /*
- * initialize the cache if needed
- */
- if (sizeCache == 0) {
- sizeCache = 10;
- oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
- sizeof(xmlNsPtr));
- if (oldNs == NULL)
- return(-1);
- newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
- sizeof(xmlNsPtr));
- if (newNs == NULL) {
- xmlFree(oldNs);
- return(-1);
- }
- }
- for (i = 0;i < nbCache;i++) {
- if (oldNs[i] == node->ns) {
- node->ns = newNs[i];
+ for (i = 0; i < nbCache; i++) {
+ if (cache[i].oldNs == node->ns) {
+ node->ns = cache[i].newNs;
break;
}
}
@@ -6519,30 +6322,31 @@
/*
* OK we need to recreate a new namespace definition
*/
- n = xmlNewReconciledNs(doc, tree, node->ns);
- if (n != NULL) { /* :-( what if else ??? */
+ n = xmlNewReconciledNs(tree, node->ns);
+ if (n == NULL) {
+ ret = -1;
+ } else {
/*
* check if we need to grow the cache buffers.
*/
if (sizeCache <= nbCache) {
- sizeCache *= 2;
- oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
- sizeof(xmlNsPtr));
- if (oldNs == NULL) {
- xmlFree(newNs);
- return(-1);
- }
- newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
- sizeof(xmlNsPtr));
- if (newNs == NULL) {
- xmlFree(oldNs);
- return(-1);
- }
+ xmlNsCache *tmp;
+ size_t newSize = sizeCache ? sizeCache * 2 : 10;
+
+ tmp = xmlRealloc(cache, newSize * sizeof(tmp[0]));
+ if (tmp == NULL) {
+ ret = -1;
+ } else {
+ cache = tmp;
+ sizeCache = newSize;
+ }
}
- newNs[nbCache] = n;
- oldNs[nbCache++] = node->ns;
- node->ns = n;
+ if (nbCache < sizeCache) {
+ cache[nbCache].newNs = n;
+ cache[nbCache++].oldNs = node->ns;
+ }
}
+ node->ns = n;
}
}
/*
@@ -6552,25 +6356,9 @@
attr = node->properties;
while (attr != NULL) {
if (attr->ns != NULL) {
- /*
- * initialize the cache if needed
- */
- if (sizeCache == 0) {
- sizeCache = 10;
- oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
- sizeof(xmlNsPtr));
- if (oldNs == NULL)
- return(-1);
- newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
- sizeof(xmlNsPtr));
- if (newNs == NULL) {
- xmlFree(oldNs);
- return(-1);
- }
- }
- for (i = 0;i < nbCache;i++) {
- if (oldNs[i] == attr->ns) {
- attr->ns = newNs[i];
+ for (i = 0; i < nbCache; i++) {
+ if (cache[i].oldNs == attr->ns) {
+ attr->ns = cache[i].newNs;
break;
}
}
@@ -6578,30 +6366,33 @@
/*
* OK we need to recreate a new namespace definition
*/
- n = xmlNewReconciledNs(doc, tree, attr->ns);
- if (n != NULL) { /* :-( what if else ??? */
+ n = xmlNewReconciledNs(tree, attr->ns);
+ if (n == NULL) {
+ ret = -1;
+ } else {
/*
* check if we need to grow the cache buffers.
*/
if (sizeCache <= nbCache) {
- sizeCache *= 2;
- oldNs = (xmlNsPtr *) xmlRealloc(oldNs,
- sizeCache * sizeof(xmlNsPtr));
- if (oldNs == NULL) {
- xmlFree(newNs);
- return(-1);
- }
- newNs = (xmlNsPtr *) xmlRealloc(newNs,
- sizeCache * sizeof(xmlNsPtr));
- if (newNs == NULL) {
- xmlFree(oldNs);
- return(-1);
- }
+ xmlNsCache *tmp;
+ size_t newSize = sizeCache ?
+ sizeCache * 2 : 10;
+
+ tmp = xmlRealloc(cache,
+ newSize * sizeof(tmp[0]));
+ if (tmp == NULL) {
+ ret = -1;
+ } else {
+ cache = tmp;
+ sizeCache = newSize;
+ }
}
- newNs[nbCache] = n;
- oldNs[nbCache++] = attr->ns;
- attr->ns = n;
+ if (nbCache < sizeCache) {
+ cache[nbCache].newNs = n;
+ cache[nbCache++].oldNs = attr->ns;
+ }
}
+ attr->ns = n;
}
}
attr = attr->next;
@@ -6637,10 +6428,8 @@
} else
break;
}
- if (oldNs != NULL)
- xmlFree(oldNs);
- if (newNs != NULL)
- xmlFree(newNs);
+ if (cache != NULL)
+ xmlFree(cache);
return(ret);
}
#endif /* LIBXML_TREE_ENABLED */
@@ -6702,7 +6491,11 @@
*/
if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
tmpstr = xmlStrdup(node->ns->prefix);
+ if (tmpstr == NULL)
+ return(NULL);
tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
+ if (tmpstr == NULL)
+ return(NULL);
tmpstr = xmlStrcat(tmpstr, node->name);
if (tmpstr == NULL)
return(NULL);
@@ -6778,23 +6571,7 @@
if (prop == NULL)
return(NULL);
if (prop->type == XML_ATTRIBUTE_NODE) {
- /*
- * Note that we return at least the empty string.
- */
- if (prop->children != NULL) {
- if ((prop->children->next == NULL) &&
- ((prop->children->type == XML_TEXT_NODE) ||
- (prop->children->type == XML_CDATA_SECTION_NODE)))
- {
- /*
- * Optimization for the common case: only 1 text node.
- */
- return(xmlStrdup(prop->children->content));
- } else {
- return(xmlNodeListGetString(prop->doc, prop->children, 1));
- }
- }
- return(xmlStrdup((xmlChar *)""));
+ return(xmlNodeGetContent((xmlNodePtr) prop));
} else if (prop->type == XML_ATTRIBUTE_DECL) {
return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
}
@@ -6808,10 +6585,11 @@
*
* Search an attribute associated to a node
* This function also looks in DTD attribute declaration for #FIXED or
- * default declaration values unless DTD use has been turned off.
+ * default declaration values.
*
* Returns the attribute or the attribute declaration or NULL if
- * neither was found.
+ * neither was found. Also returns NULL if a memory allocation failed
+ * making this function unreliable.
*/
xmlAttrPtr
xmlHasProp(const xmlNode *node, const xmlChar *name) {
@@ -6861,11 +6639,12 @@
* This attribute has to be anchored in the namespace specified.
* This does the entity substitution.
* This function looks in DTD attribute declaration for #FIXED or
- * default declaration values unless DTD use has been turned off.
+ * default declaration values.
* Note that a namespace of NULL indicates to use the default namespace.
*
- * Returns the attribute or the attribute declaration or NULL
- * if neither was found.
+ * Returns the attribute or the attribute declaration or NULL if
+ * neither was found. Also returns NULL if a memory allocation failed
+ * making this function unreliable.
*/
xmlAttrPtr
xmlHasNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) {
@@ -7055,8 +6834,10 @@
*/
xmlAttrPtr
xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
- int len;
- const xmlChar *nqname;
+ xmlNsPtr ns = NULL;
+ const xmlChar *localname;
+ xmlChar *prefix;
+ int res;
if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
return(NULL);
@@ -7064,16 +6845,19 @@
/*
* handle QNames
*/
- nqname = xmlSplitQName3(name, &len);
- if (nqname != NULL) {
- xmlNsPtr ns;
- xmlChar *prefix = xmlStrndup(name, len);
- ns = xmlSearchNs(node->doc, node, prefix);
- if (prefix != NULL)
- xmlFree(prefix);
- if (ns != NULL)
- return(xmlSetNsProp(node, ns, nqname, value));
+ localname = xmlSplitQName4(name, &prefix);
+ if (localname == NULL)
+ return(NULL);
+
+ if (prefix != NULL) {
+ res = xmlSearchNsSafe(node, prefix, &ns);
+ xmlFree(prefix);
+ if (res < 0)
+ return(NULL);
+ if (ns != NULL)
+ return(xmlSetNsProp(node, ns, localname, value));
}
+
return(xmlSetNsProp(node, NULL, name, value));
}
@@ -7097,6 +6881,8 @@
if (ns && (ns->href == NULL))
return(NULL);
+ if (name == NULL)
+ return(NULL);
prop = xmlGetPropNodeInternal(node, name,
(ns != NULL) ? ns->href : NULL, 0);
if (prop != NULL) {
@@ -7134,7 +6920,7 @@
}
}
if ((prop->atype == XML_ATTRIBUTE_ID) &&
- (xmlAddIDSafe(node->doc, value, prop, 0, NULL) < 0)) {
+ (xmlAddIDSafe(prop, value) < 0)) {
return(NULL);
}
return(prop);
@@ -7195,33 +6981,25 @@
* @content: the content
* @len: @content length
*
- * Concat the given string at the end of the existing node content
+ * Concat the given string at the end of the existing node content.
+ *
+ * If @len is -1, the string length will be calculated.
*
* Returns -1 in case of error, 0 otherwise
*/
int
xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
- if (node == NULL) return(-1);
+ if (node == NULL)
+ return(-1);
if ((node->type != XML_TEXT_NODE) &&
(node->type != XML_CDATA_SECTION_NODE) &&
(node->type != XML_COMMENT_NODE) &&
- (node->type != XML_PI_NODE)) {
+ (node->type != XML_PI_NODE))
return(-1);
- }
- /* need to check if content is currently in the dictionary */
- if ((node->content == (xmlChar *) &(node->properties)) ||
- ((node->doc != NULL) && (node->doc->dict != NULL) &&
- xmlDictOwns(node->doc->dict, node->content))) {
- node->content = xmlStrncatNew(node->content, content, len);
- } else {
- node->content = xmlStrncat(node->content, content, len);
- }
- node->properties = NULL;
- if (node->content == NULL)
- return(-1);
- return(0);
+
+ return(xmlTextAddContent(node, content, len));
}
/************************************************************************
@@ -8249,39 +8027,6 @@
}
/*
-* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
-* otherwise copy it, when it was in the source-dict.
-*/
-#define XML_TREE_ADOPT_STR(str) \
- if (adoptStr && (str != NULL)) { \
- if (destDoc->dict) { \
- const xmlChar *old = str; \
- str = xmlDictLookup(destDoc->dict, str, -1); \
- if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
- (!xmlDictOwns(sourceDoc->dict, old))) \
- xmlFree((char *)old); \
- } else if ((sourceDoc) && (sourceDoc->dict) && \
- xmlDictOwns(sourceDoc->dict, str)) { \
- str = BAD_CAST xmlStrdup(str); \
- } \
- }
-
-/*
-* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
-* put it in dest-dict or copy it.
-*/
-#define XML_TREE_ADOPT_STR_2(str) \
- if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
- (sourceDoc->dict != NULL) && \
- xmlDictOwns(sourceDoc->dict, cur->content)) { \
- if (destDoc->dict) \
- cur->content = (xmlChar *) \
- xmlDictLookup(destDoc->dict, cur->content, -1); \
- else \
- cur->content = xmlStrdup(BAD_CAST cur->content); \
- }
-
-/*
* xmlDOMWrapNSNormAddNsMapItem2:
*
* For internal use. Adds a ns-decl mapping.
@@ -8292,19 +8037,18 @@
xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
xmlNsPtr oldNs, xmlNsPtr newNs)
{
- if (*list == NULL) {
- *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
- if (*list == NULL)
- return(-1);
- *size = 3;
- *number = 0;
- } else if ((*number) >= (*size)) {
- *size *= 2;
- *list = (xmlNsPtr *) xmlRealloc(*list,
- (*size) * 2 * sizeof(xmlNsPtr));
- if (*list == NULL)
- return(-1);
+ if (*number >= *size) {
+ xmlNsPtr *tmp;
+ size_t newSize;
+
+ newSize = *size ? *size * 2 : 3;
+ tmp = xmlRealloc(*list, newSize * 2 * sizeof(tmp[0]));
+ if (tmp == NULL)
+ return(-1);
+ *list = tmp;
+ *size = newSize;
}
+
(*list)[2 * (*number)] = oldNs;
(*list)[2 * (*number) +1] = newNs;
(*number)++;
@@ -8333,7 +8077,7 @@
xmlNodePtr node, int options ATTRIBUTE_UNUSED)
{
xmlNsPtr *list = NULL;
- int sizeList, nbList, i, j;
+ int sizeList = 0, nbList = 0, ret = 0, i, j;
xmlNsPtr ns;
if ((node == NULL) || (doc == NULL) || (node->doc != doc))
@@ -8369,7 +8113,7 @@
do {
if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
&nbList, ns, ns) == -1)
- goto internal_error;
+ ret = -1;
ns = ns->next;
} while (ns != NULL);
}
@@ -8399,7 +8143,7 @@
ns = xmlDOMWrapStoreNs(doc, node->ns->href,
node->ns->prefix);
if (ns == NULL)
- goto internal_error;
+ ret = -1;
}
if (ns != NULL) {
/*
@@ -8407,7 +8151,7 @@
*/
if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
&nbList, node->ns, ns) == -1)
- goto internal_error;
+ ret = -1;
}
node->ns = ns;
}
@@ -8432,19 +8176,22 @@
if (node->next != NULL)
node = node->next;
else {
+ int type = node->type;
+
node = node->parent;
- goto next_sibling;
+ if ((type == XML_ATTRIBUTE_NODE) &&
+ (node != NULL) &&
+ (node->children != NULL)) {
+ node = node->children;
+ } else {
+ goto next_sibling;
+ }
}
} while (node != NULL);
if (list != NULL)
xmlFree(list);
- return (0);
-
-internal_error:
- if (list != NULL)
- xmlFree(list);
- return (-1);
+ return (ret);
}
/*
@@ -8542,8 +8289,7 @@
out = prev;
prev = cur;
}
- } else if ((cur->type == XML_ENTITY_NODE) ||
- (cur->type == XML_ENTITY_DECL))
+ } else if (cur->type == XML_ENTITY_DECL)
return (0);
cur = cur->parent;
} while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
@@ -8605,8 +8351,7 @@
ns = ns->next;
} while (ns != NULL);
}
- } else if ((cur->type == XML_ENTITY_NODE) ||
- (cur->type == XML_ENTITY_DECL))
+ } else if (cur->type == XML_ENTITY_DECL)
return (0);
cur = cur->parent;
} while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
@@ -8790,7 +8535,6 @@
*/
if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
tmpns, XML_TREE_NSMAP_DOC) == NULL) {
- xmlFreeNs(tmpns);
return (-1);
}
*retNs = tmpns;
@@ -8820,7 +8564,6 @@
}
}
if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
- xmlFreeNs(tmpns);
return (-1);
}
*retNs = tmpns;
@@ -8865,7 +8608,7 @@
int optRemoveRedundantNS =
((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
xmlNsPtr *listRedund = NULL;
- int sizeRedund = 0, nbRedund = 0, ret, i, j;
+ int sizeRedund = 0, nbRedund = 0, ret = 0, i, j;
if ((elem == NULL) || (elem->doc == NULL) ||
(elem->type != XML_ELEMENT_NODE))
@@ -8894,7 +8637,7 @@
*/
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
elem->parent) == -1)
- goto internal_error;
+ ret = -1;
}
parnsdone = 1;
}
@@ -8916,16 +8659,18 @@
* Add it to the list of redundant ns-decls.
*/
if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
- &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
- goto internal_error;
- /*
- * Remove the ns-decl from the element-node.
- */
- if (prevns)
- prevns->next = ns->next;
- else
- cur->nsDef = ns->next;
- goto next_ns_decl;
+ &sizeRedund, &nbRedund, ns, mi->newNs) == -1) {
+ ret = -1;
+ } else {
+ /*
+ * Remove the ns-decl from the element-node.
+ */
+ if (prevns)
+ prevns->next = ns->next;
+ else
+ cur->nsDef = ns->next;
+ goto next_ns_decl;
+ }
}
}
}
@@ -8955,7 +8700,7 @@
*/
if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
depth) == NULL)
- goto internal_error;
+ ret = -1;
prevns = ns;
next_ns_decl:
@@ -8975,7 +8720,7 @@
((xmlNodePtr) elem->parent->doc != elem->parent)) {
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
elem->parent) == -1)
- goto internal_error;
+ ret = -1;
}
parnsdone = 1;
}
@@ -9014,7 +8759,7 @@
&nsMap, depth,
ancestorsOnly,
(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
- goto internal_error;
+ ret = -1;
cur->ns = ns;
ns_end:
@@ -9074,11 +8819,6 @@
}
} while (cur != NULL);
- ret = 0;
- goto exit;
-internal_error:
- ret = -1;
-exit:
if (listRedund) {
for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
xmlFreeNs(listRedund[j]);
@@ -9114,7 +8854,7 @@
*/
static int
xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
- xmlDocPtr sourceDoc,
+ xmlDocPtr sourceDoc ATTRIBUTE_UNUSED,
xmlNodePtr node,
xmlDocPtr destDoc,
xmlNodePtr destParent,
@@ -9125,22 +8865,13 @@
xmlNsMapPtr nsMap = NULL;
xmlNsMapItemPtr mi;
xmlNsPtr ns = NULL;
- int depth = -1, adoptStr = 1;
+ int depth = -1;
/* gather @parent's ns-decls. */
int parnsdone;
/* @ancestorsOnly should be set per option. */
int ancestorsOnly = 0;
/*
- * Optimize string adoption for equal or none dicts.
- */
- if ((sourceDoc != NULL) &&
- (sourceDoc->dict == destDoc->dict))
- adoptStr = 0;
- else
- adoptStr = 1;
-
- /*
* Get the ns-map from the context if available.
*/
if (ctxt)
@@ -9159,40 +8890,21 @@
parnsdone = 0;
cur = node;
- if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
- goto internal_error;
while (cur != NULL) {
- /*
- * Paranoid source-doc sanity check.
- */
- if (cur->doc != sourceDoc) {
- /*
- * We'll assume XIncluded nodes if the doc differs.
- * TODO: Do we need to reconciliate XIncluded nodes?
- * This here skips XIncluded nodes and tries to handle
- * broken sequences.
- */
- if (cur->next == NULL)
- goto leave_node;
- do {
- cur = cur->next;
- if ((cur->type == XML_XINCLUDE_END) ||
- (cur->doc == node->doc))
- break;
- } while (cur->next != NULL);
+ if (cur->doc != destDoc) {
+ if (xmlNodeSetDoc(cur, destDoc) < 0)
+ ret = -1;
+ }
- if (cur->doc != node->doc)
- goto leave_node;
- }
- cur->doc = destDoc;
switch (cur->type) {
case XML_XINCLUDE_START:
case XML_XINCLUDE_END:
/*
* TODO
*/
- return (-1);
+ ret = -1;
+ goto leave_node;
case XML_ELEMENT_NODE:
curElem = cur;
depth++;
@@ -9213,14 +8925,12 @@
*/
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
destParent) == -1)
- goto internal_error;
+ ret = -1;
parnsdone = 1;
}
for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
/*
* NOTE: ns->prefix and ns->href are never in the dict.
- * XML_TREE_ADOPT_STR(ns->prefix)
- * XML_TREE_ADOPT_STR(ns->href)
*/
/*
* Does it shadow any ns-decl?
@@ -9242,7 +8952,7 @@
*/
if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
ns, ns, depth) == NULL)
- goto internal_error;
+ ret = -1;
}
}
/* Falls through. */
@@ -9254,7 +8964,7 @@
if (! parnsdone) {
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
destParent) == -1)
- goto internal_error;
+ ret = -1;
parnsdone = 1;
}
/*
@@ -9288,7 +8998,7 @@
*/
if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
- goto internal_error;
+ ret = -1;
cur->ns = ns;
} else {
/*
@@ -9302,15 +9012,11 @@
ancestorsOnly,
/* ns-decls must be prefixed for attributes. */
(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
- goto internal_error;
+ ret = -1;
cur->ns = ns;
}
+
ns_end:
- /*
- * Further node properties.
- * TODO: Is this all?
- */
- XML_TREE_ADOPT_STR(cur->name)
if (cur->type == XML_ELEMENT_NODE) {
cur->psvi = NULL;
cur->line = 0;
@@ -9325,55 +9031,16 @@
cur = (xmlNodePtr) cur->properties;
continue;
}
- } else {
- /*
- * Attributes.
- */
- if ((sourceDoc != NULL) &&
- (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
- {
- xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
- }
- ((xmlAttrPtr) cur)->atype = 0;
- ((xmlAttrPtr) cur)->psvi = NULL;
}
break;
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
- /*
- * This puts the content in the dest dict, only if
- * it was previously in the source dict.
- */
- XML_TREE_ADOPT_STR_2(cur->content)
- goto leave_node;
- case XML_ENTITY_REF_NODE:
- /*
- * Remove reference to the entity-node.
- */
- cur->content = NULL;
- cur->children = NULL;
- cur->last = NULL;
- if ((destDoc->intSubset) || (destDoc->extSubset)) {
- xmlEntityPtr ent;
- /*
- * Assign new entity-node if available.
- */
- ent = xmlGetDocEntity(destDoc, cur->name);
- if (ent != NULL) {
- cur->content = ent->content;
- cur->children = (xmlNodePtr) ent;
- cur->last = (xmlNodePtr) ent;
- }
- }
- goto leave_node;
case XML_PI_NODE:
- XML_TREE_ADOPT_STR(cur->name)
- XML_TREE_ADOPT_STR_2(cur->content)
- break;
case XML_COMMENT_NODE:
- break;
+ case XML_ENTITY_REF_NODE:
+ goto leave_node;
default:
- goto internal_error;
+ ret = -1;
}
/*
* Walk the tree.
@@ -9424,12 +9091,6 @@
}
}
- goto exit;
-
-internal_error:
- ret = -1;
-
-exit:
/*
* Cleanup.
*/
@@ -9491,7 +9152,7 @@
int options ATTRIBUTE_UNUSED)
{
int ret = 0;
- xmlNodePtr cur, curElem = NULL;
+ xmlNodePtr cur, cloneElem = NULL;
xmlNsMapPtr nsMap = NULL;
xmlNsMapItemPtr mi;
xmlNsPtr ns;
@@ -9509,7 +9170,8 @@
xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
xmlDictPtr dict; /* The destination dict */
- if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
+ if ((node == NULL) || (resNode == NULL) || (destDoc == NULL) ||
+ ((destParent != NULL) && (destParent->doc != destDoc)))
return(-1);
/*
* TODO: Initially we support only element-nodes.
@@ -9571,7 +9233,6 @@
case XML_PI_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
/*
* Nodes of xmlNode structure.
*/
@@ -9589,6 +9250,7 @@
clone->prev = prevClone;
} else
parentClone->children = clone;
+ parentClone->last = clone;
} else
resultClone = clone;
@@ -9641,7 +9303,12 @@
else if (cur->name == xmlStringComment)
clone->name = xmlStringComment;
else if (cur->name != NULL) {
- DICT_CONST_COPY(cur->name, clone->name);
+ if (dict != NULL)
+ clone->name = xmlDictLookup(dict, cur->name, -1);
+ else
+ clone->name = xmlStrdup(cur->name);
+ if (clone->name == NULL)
+ goto internal_error;
}
switch (cur->type) {
@@ -9652,7 +9319,7 @@
*/
return (-1);
case XML_ELEMENT_NODE:
- curElem = cur;
+ cloneElem = clone;
depth++;
/*
* Namespace declarations.
@@ -9679,14 +9346,24 @@
*/
cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
if (cloneNs == NULL)
- return(-1);
+ goto internal_error;
memset(cloneNs, 0, sizeof(xmlNs));
cloneNs->type = XML_LOCAL_NAMESPACE;
- if (ns->href != NULL)
+ if (ns->href != NULL) {
cloneNs->href = xmlStrdup(ns->href);
- if (ns->prefix != NULL)
+ if (cloneNs->href == NULL) {
+ xmlFreeNs(cloneNs);
+ goto internal_error;
+ }
+ }
+ if (ns->prefix != NULL) {
cloneNs->prefix = xmlStrdup(ns->prefix);
+ if (cloneNs->prefix == NULL) {
+ xmlFreeNs(cloneNs);
+ goto internal_error;
+ }
+ }
*cloneNsDefSlot = cloneNs;
cloneNsDefSlot = &(cloneNs->next);
@@ -9732,15 +9409,18 @@
/* IDs will be processed further down. */
/* cur->ns will be processed further down. */
break;
+ case XML_PI_NODE:
+ case XML_COMMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
/*
* Note that this will also cover the values of attributes.
*/
- DICT_COPY(cur->content, clone->content);
- goto leave_node;
- case XML_ENTITY_NODE:
- /* TODO: What to do here? */
+ if (cur->content != NULL) {
+ clone->content = xmlStrdup(cur->content);
+ if (clone->content == NULL)
+ goto internal_error;
+ }
goto leave_node;
case XML_ENTITY_REF_NODE:
if (sourceDoc != destDoc) {
@@ -9766,12 +9446,6 @@
clone->last = cur->last;
}
goto leave_node;
- case XML_PI_NODE:
- DICT_COPY(cur->content, clone->content);
- goto leave_node;
- case XML_COMMENT_NODE:
- DICT_COPY(cur->content, clone->content);
- goto leave_node;
default:
goto internal_error;
}
@@ -9831,8 +9505,8 @@
* Acquire a normalized ns-decl and add it to the map.
*/
if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc,
- /* ns-decls on curElem or on destDoc->oldNs */
- destParent ? curElem : NULL,
+ /* ns-decls on cloneElem or on destDoc->oldNs */
+ destParent ? cloneElem : NULL,
cur->ns, &ns,
&nsMap, depth,
/* if we need to search only in the ancestor-axis */
@@ -9853,20 +9527,22 @@
if ((clone->type == XML_ATTRIBUTE_NODE) &&
(clone->parent != NULL))
{
- if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
+ int res;
+ res = xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone);
+ if (res < 0)
+ goto internal_error;
+ if (res == 1) {
xmlChar *idVal;
- idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
- if (idVal != NULL) {
- if (xmlAddIDSafe(destDoc, idVal, (xmlAttrPtr) cur, 0,
- NULL) < 0) {
- /* TODO: error message. */
- xmlFree(idVal);
- goto internal_error;
- }
- xmlFree(idVal);
- }
+ idVal = xmlNodeGetContent(cur);
+ if (idVal == NULL)
+ goto internal_error;
+ if (xmlAddIDSafe((xmlAttrPtr) cur, idVal) < 0) {
+ xmlFree(idVal);
+ goto internal_error;
+ }
+ xmlFree(idVal);
}
}
/*
@@ -9931,11 +9607,6 @@
prevClone = clone;
cur = cur->next;
} else if (cur->type != XML_ATTRIBUTE_NODE) {
- /*
- * Set clone->last.
- */
- if (clone->parent != NULL)
- clone->parent->last = clone;
clone = clone->parent;
if (clone != NULL)
parentClone = clone->parent;
@@ -10004,19 +9675,22 @@
*/
static int
xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
- xmlDocPtr sourceDoc,
+ xmlDocPtr sourceDoc ATTRIBUTE_UNUSED,
xmlAttrPtr attr,
xmlDocPtr destDoc,
xmlNodePtr destParent,
int options ATTRIBUTE_UNUSED)
{
- xmlNodePtr cur;
- int adoptStr = 1;
+ int ret = 0;
if ((attr == NULL) || (destDoc == NULL))
return (-1);
- attr->doc = destDoc;
+ if (attr->doc != destDoc) {
+ if (xmlSetTreeDoc((xmlNodePtr) attr, destDoc) < 0)
+ ret = -1;
+ }
+
if (attr->ns != NULL) {
xmlNsPtr ns = NULL;
@@ -10037,75 +9711,18 @@
*/
if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
&ns, 1) == -1)
- goto internal_error;
+ ret = -1;
if (ns == NULL) {
ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
attr->ns->href, attr->ns->prefix, 1);
}
}
if (ns == NULL)
- goto internal_error;
+ ret = -1;
attr->ns = ns;
}
- XML_TREE_ADOPT_STR(attr->name);
- attr->atype = 0;
- attr->psvi = NULL;
- /*
- * Walk content.
- */
- if (attr->children == NULL)
- return (0);
- cur = attr->children;
- if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
- goto internal_error;
- while (cur != NULL) {
- cur->doc = destDoc;
- switch (cur->type) {
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- XML_TREE_ADOPT_STR_2(cur->content)
- break;
- case XML_ENTITY_REF_NODE:
- /*
- * Remove reference to the entity-node.
- */
- cur->content = NULL;
- cur->children = NULL;
- cur->last = NULL;
- if ((destDoc->intSubset) || (destDoc->extSubset)) {
- xmlEntityPtr ent;
- /*
- * Assign new entity-node if available.
- */
- ent = xmlGetDocEntity(destDoc, cur->name);
- if (ent != NULL) {
- cur->content = ent->content;
- cur->children = (xmlNodePtr) ent;
- cur->last = (xmlNodePtr) ent;
- }
- }
- break;
- default:
- break;
- }
- if (cur->children != NULL) {
- cur = cur->children;
- continue;
- }
-next_sibling:
- if (cur == (xmlNodePtr) attr)
- break;
- if (cur->next != NULL)
- cur = cur->next;
- else {
- cur = cur->parent;
- goto next_sibling;
- }
- }
- return (0);
-internal_error:
- return (-1);
+ return (ret);
}
/*
@@ -10143,6 +9760,8 @@
xmlNodePtr destParent,
int options)
{
+ int ret = 0;
+
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
(destDoc == NULL) ||
((destParent != NULL) && (destParent->doc != destDoc)))
@@ -10150,17 +9769,18 @@
/*
* Check node->doc sanity.
*/
- if ((node->doc != NULL) && (sourceDoc != NULL) &&
- (node->doc != sourceDoc)) {
- /*
- * Might be an XIncluded node.
- */
+ if (sourceDoc == NULL) {
+ sourceDoc = node->doc;
+ } else if (node->doc != sourceDoc) {
return (-1);
}
- if (sourceDoc == NULL)
- sourceDoc = node->doc;
+
+ /*
+ * TODO: Shouldn't this be allowed?
+ */
if (sourceDoc == destDoc)
return (-1);
+
switch (node->type) {
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
@@ -10189,52 +9809,12 @@
return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
(xmlAttrPtr) node, destDoc, destParent, options));
} else {
- xmlNodePtr cur = node;
- int adoptStr = 1;
-
- cur->doc = destDoc;
- /*
- * Optimize string adoption.
- */
- if ((sourceDoc != NULL) &&
- (sourceDoc->dict == destDoc->dict))
- adoptStr = 0;
- switch (node->type) {
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- XML_TREE_ADOPT_STR_2(node->content)
- break;
- case XML_ENTITY_REF_NODE:
- /*
- * Remove reference to the entity-node.
- */
- node->content = NULL;
- node->children = NULL;
- node->last = NULL;
- if ((destDoc->intSubset) || (destDoc->extSubset)) {
- xmlEntityPtr ent;
- /*
- * Assign new entity-node if available.
- */
- ent = xmlGetDocEntity(destDoc, node->name);
- if (ent != NULL) {
- node->content = ent->content;
- node->children = (xmlNodePtr) ent;
- node->last = (xmlNodePtr) ent;
- }
- }
- XML_TREE_ADOPT_STR(node->name)
- break;
- case XML_PI_NODE: {
- XML_TREE_ADOPT_STR(node->name)
- XML_TREE_ADOPT_STR_2(node->content)
- break;
- }
- default:
- break;
- }
+ if (node->doc != destDoc) {
+ if (xmlNodeSetDoc(node, destDoc) < 0)
+ ret = -1;
+ }
}
- return (0);
+ return (ret);
}
/************************************************************************
diff --git a/src/valid.c b/src/valid.c
index ada36a6..897a368 100644
--- a/src/valid.c
+++ b/src/valid.c
@@ -74,7 +74,9 @@
xmlParserCtxtPtr pctxt = NULL;
va_list ap;
- if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT))
+ if (ctxt == NULL)
+ return;
+ if (ctxt->flags & XML_VCTXT_USE_PCTXT)
pctxt = ctxt->userData;
va_start(ap, msg);
@@ -590,6 +592,8 @@
* @ctxt: a validation context
* @elem: an element declaration node
*
+ * DEPRECATED: Internal function, don't use.
+ *
* (Re)Build the automata associated to the content model of this
* element
*
@@ -1184,9 +1188,8 @@
}
break;
default:
- xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
- "Internal: ELEMENT decl corrupted invalid type\n",
- NULL);
+ xmlErrValid(ctxt, XML_ERR_ARGUMENT,
+ "xmlAddElementDecl: invalid type\n", NULL);
return(NULL);
}
@@ -1423,7 +1426,8 @@
save = xmlSaveToBuffer(buf, NULL, 0);
xmlSaveTree(save, (xmlNodePtr) elem);
- xmlSaveClose(save);
+ if (xmlSaveFinish(save) != XML_ERR_OK)
+ xmlFree(xmlBufferDetach(buf));
}
/**
@@ -1435,9 +1439,9 @@
* the arguments.
*/
static void
-xmlDumpElementDeclScan(void *elem, void *buf,
+xmlDumpElementDeclScan(void *elem, void *save,
const xmlChar *name ATTRIBUTE_UNUSED) {
- xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);
+ xmlSaveTree(save, elem);
}
/**
@@ -1451,9 +1455,15 @@
*/
void
xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
+ xmlSaveCtxtPtr save;
+
if ((buf == NULL) || (table == NULL))
return;
- xmlHashScan(table, xmlDumpElementDeclScan, buf);
+
+ save = xmlSaveToBuffer(buf, NULL, 0);
+ xmlHashScan(table, xmlDumpElementDeclScan, save);
+ if (xmlSaveFinish(save) != XML_ERR_OK)
+ xmlFree(xmlBufferDetach(buf));
}
#endif /* LIBXML_OUTPUT_ENABLED */
@@ -1686,9 +1696,8 @@
case XML_ATTRIBUTE_NOTATION:
break;
default:
- xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
- "Internal: ATTRIBUTE struct corrupted invalid type\n",
- NULL);
+ xmlErrValid(ctxt, XML_ERR_ARGUMENT,
+ "xmlAddAttributeDecl: invalid type\n", NULL);
xmlFreeEnumeration(tree);
return(NULL);
}
@@ -1770,9 +1779,13 @@
else
ret->defaultValue = xmlStrdup(defaultValue);
if (ret->defaultValue == NULL)
- xmlVErrMemory(ctxt);
+ goto mem_error;
}
+ elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem);
+ if (elemDef == NULL)
+ goto mem_error;
+
/*
* Validity Check:
* Search the DTD for previous declarations of the ATTLIST
@@ -1798,48 +1811,44 @@
* Validity Check:
* Multiple ID per element
*/
- elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem);
- if (elemDef != NULL) {
-
#ifdef LIBXML_VALID_ENABLED
- if ((type == XML_ATTRIBUTE_ID) &&
- (xmlScanIDAttributeDecl(ctxt, elemDef, 1) != 0)) {
- xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
- "Element %s has too may ID attributes defined : %s\n",
- elem, name, NULL);
- if (ctxt != NULL)
- ctxt->valid = 0;
- }
+ if ((type == XML_ATTRIBUTE_ID) &&
+ (xmlScanIDAttributeDecl(ctxt, elemDef, 1) != 0)) {
+ xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
+ "Element %s has too may ID attributes defined : %s\n",
+ elem, name, NULL);
+ if (ctxt != NULL)
+ ctxt->valid = 0;
+ }
#endif /* LIBXML_VALID_ENABLED */
- /*
- * Insert namespace default def first they need to be
- * processed first.
- */
- if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
- ((ret->prefix != NULL &&
- (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
- ret->nexth = elemDef->attributes;
- elemDef->attributes = ret;
- } else {
- xmlAttributePtr tmp = elemDef->attributes;
+ /*
+ * Insert namespace default def first they need to be
+ * processed first.
+ */
+ if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
+ ((ret->prefix != NULL &&
+ (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
+ ret->nexth = elemDef->attributes;
+ elemDef->attributes = ret;
+ } else {
+ xmlAttributePtr tmp = elemDef->attributes;
- while ((tmp != NULL) &&
- ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
- ((ret->prefix != NULL &&
- (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
- if (tmp->nexth == NULL)
- break;
- tmp = tmp->nexth;
- }
- if (tmp != NULL) {
- ret->nexth = tmp->nexth;
- tmp->nexth = ret;
- } else {
- ret->nexth = elemDef->attributes;
- elemDef->attributes = ret;
- }
- }
+ while ((tmp != NULL) &&
+ ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
+ ((ret->prefix != NULL &&
+ (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
+ if (tmp->nexth == NULL)
+ break;
+ tmp = tmp->nexth;
+ }
+ if (tmp != NULL) {
+ ret->nexth = tmp->nexth;
+ tmp->nexth = ret;
+ } else {
+ ret->nexth = elemDef->attributes;
+ elemDef->attributes = ret;
+ }
}
/*
@@ -1966,7 +1975,8 @@
save = xmlSaveToBuffer(buf, NULL, 0);
xmlSaveTree(save, (xmlNodePtr) attr);
- xmlSaveClose(save);
+ if (xmlSaveFinish(save) != XML_ERR_OK)
+ xmlFree(xmlBufferDetach(buf));
}
/**
@@ -1977,9 +1987,9 @@
* This is used with the hash scan function - just reverses arguments
*/
static void
-xmlDumpAttributeDeclScan(void *attr, void *buf,
+xmlDumpAttributeDeclScan(void *attr, void *save,
const xmlChar *name ATTRIBUTE_UNUSED) {
- xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);
+ xmlSaveTree(save, attr);
}
/**
@@ -1993,9 +2003,15 @@
*/
void
xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
+ xmlSaveCtxtPtr save;
+
if ((buf == NULL) || (table == NULL))
return;
- xmlHashScan(table, xmlDumpAttributeDeclScan, buf);
+
+ save = xmlSaveToBuffer(buf, NULL, 0);
+ xmlHashScan(table, xmlDumpAttributeDeclScan, save);
+ if (xmlSaveFinish(save) != XML_ERR_OK)
+ xmlFree(xmlBufferDetach(buf));
}
#endif /* LIBXML_OUTPUT_ENABLED */
@@ -2202,7 +2218,8 @@
save = xmlSaveToBuffer(buf, NULL, 0);
xmlSaveNotationDecl(save, nota);
- xmlSaveClose(save);
+ if (xmlSaveFinish(save) != XML_ERR_OK)
+ xmlFree(xmlBufferDetach(buf));
}
/**
@@ -2223,7 +2240,8 @@
save = xmlSaveToBuffer(buf, NULL, 0);
xmlSaveNotationTable(save, table);
- xmlSaveClose(save);
+ if (xmlSaveFinish(save) != XML_ERR_OK)
+ xmlFree(xmlBufferDetach(buf));
}
#endif /* LIBXML_OUTPUT_ENABLED */
@@ -2275,40 +2293,46 @@
DICT_FREE(id->value)
if (id->name != NULL)
DICT_FREE(id->name)
+ if (id->attr != NULL) {
+ id->attr->id = NULL;
+ id->attr->atype = 0;
+ }
+
xmlFree(id);
}
/**
- * xmlAddIDSafe:
- * @doc: pointer to the document
- * @value: the value name
+ * xmlAddIDInternal:
* @attr: the attribute holding the ID
- * @id: pointer to new xmlIdPtr (optional)
+ * @value: the attribute (ID) value
+ * @idPtr: pointer to resulting ID
*
* Register a new id declaration
*
* Returns 1 on success, 0 if the ID already exists, -1 if a memory
* allocation fails.
*/
-int
-xmlAddIDSafe(xmlDocPtr doc, const xmlChar *value, xmlAttrPtr attr,
- int streaming, xmlIDPtr *id) {
- xmlIDPtr ret;
+static int
+xmlAddIDInternal(xmlAttrPtr attr, const xmlChar *value, xmlIDPtr *idPtr) {
+ xmlDocPtr doc;
+ xmlIDPtr id;
xmlIDTablePtr table;
+ int ret;
- if (id != NULL)
- *id = NULL;
-
- if (doc == NULL) {
- return(-1);
- }
- if ((value == NULL) || (value[0] == 0)) {
+ if (idPtr != NULL)
+ *idPtr = NULL;
+ if ((value == NULL) || (value[0] == 0))
return(0);
- }
- if (attr == NULL) {
- return(-1);
- }
+ if (attr == NULL)
+ return(0);
+
+ doc = attr->doc;
+ if (doc == NULL)
+ return(0);
+
+ if (attr->id != NULL)
+ xmlRemoveID(doc, attr);
/*
* Create the ID table if needed.
@@ -2319,69 +2343,63 @@
if (table == NULL)
return(-1);
} else {
- ret = xmlHashLookup(table, value);
- if (ret != NULL) {
- /*
- * Update the attribute unless we are parsing in streaming
- * mode. If the attribute is copied from an entity we want
- * the ID reference the copy.
- */
- if (ret->attr != NULL) {
- ret->attr->id = NULL;
- ret->attr = attr;
- attr->id = ret;
+ id = xmlHashLookup(table, value);
+ if (id != NULL) {
+ if (id->attr != NULL) {
+ id->attr->id = NULL;
+ id->attr->atype = 0;
}
- ret->lineno = xmlGetLineNo(attr->parent);
- attr->atype = XML_ATTRIBUTE_ID;
- return(0);
+ ret = 0;
+ goto done;
}
}
- ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
- if (ret == NULL)
+ id = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
+ if (id == NULL)
return(-1);
- memset(ret, 0, sizeof(*ret));
+ memset(id, 0, sizeof(*id));
/*
* fill the structure.
*/
- ret->doc = doc;
- ret->value = xmlStrdup(value);
- if (ret->value == NULL) {
- xmlFreeID(ret);
+ id->doc = doc;
+ id->value = xmlStrdup(value);
+ if (id->value == NULL) {
+ xmlFreeID(id);
return(-1);
}
- if (streaming) {
- /*
- * Operating in streaming mode, attr is gonna disappear
- */
- if (doc->dict != NULL)
- ret->name = xmlDictLookup(doc->dict, attr->name, -1);
- else
- ret->name = xmlStrdup(attr->name);
- if (ret->name == NULL) {
- xmlFreeID(ret);
- return(-1);
- }
- ret->attr = NULL;
- } else {
- ret->attr = attr;
- ret->name = NULL;
- }
- ret->lineno = xmlGetLineNo(attr->parent);
- if (xmlHashAddEntry(table, value, ret) < 0) {
- xmlFreeID(ret);
+ if (xmlHashAddEntry(table, value, id) < 0) {
+ xmlFreeID(id);
return(-1);
}
- attr->atype = XML_ATTRIBUTE_ID;
- if (!streaming)
- attr->id = ret;
+ ret = 1;
+ if (idPtr != NULL)
+ *idPtr = id;
- if (id != NULL)
- *id = ret;
- return(1);
+done:
+ id->attr = attr;
+ id->lineno = xmlGetLineNo(attr->parent);
+ attr->atype = XML_ATTRIBUTE_ID;
+ attr->id = id;
+
+ return(ret);
+}
+
+/**
+ * xmlAddIDSafe:
+ * @attr: the attribute holding the ID
+ * @value: the attribute (ID) value
+ *
+ * Register a new id declaration
+ *
+ * Returns 1 on success, 0 if the ID already exists, -1 if a memory
+ * allocation fails.
+ */
+int
+xmlAddIDSafe(xmlAttrPtr attr, const xmlChar *value) {
+ return(xmlAddIDInternal(attr, value, NULL));
}
/**
@@ -2401,7 +2419,10 @@
xmlIDPtr id;
int res;
- res = xmlAddIDSafe(doc, value, attr, xmlIsStreaming(ctxt), &id);
+ if ((attr == NULL) || (doc != attr->doc))
+ return(NULL);
+
+ res = xmlAddIDInternal(attr, value, &id);
if (res < 0) {
xmlVErrMemory(ctxt);
}
@@ -2452,30 +2473,39 @@
*/
int
xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
- if ((attr == NULL) || (attr->name == NULL)) return(0);
- if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
- (!strcmp((char *) attr->name, "id")) &&
- (!strcmp((char *) attr->ns->prefix, "xml")))
- return(1);
- if (doc == NULL) return(0);
- if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
- (doc->type != XML_HTML_DOCUMENT_NODE)) {
- return(0);
- } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
- if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
- ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
- ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
+ if ((attr == NULL) || (attr->name == NULL))
+ return(0);
+
+ if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
+ if (xmlStrEqual(BAD_CAST "id", attr->name))
+ return(1);
+
+ if ((elem == NULL) || (elem->type != XML_ELEMENT_NODE))
+ return(0);
+
+ if ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
+ (xmlStrEqual(elem->name, BAD_CAST "a")))
return(1);
- return(0);
- } else if (elem == NULL) {
- return(0);
} else {
xmlAttributePtr attrDecl = NULL;
-
xmlChar felem[50];
xmlChar *fullelemname;
const xmlChar *aprefix;
+ if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
+ (!strcmp((char *) attr->name, "id")) &&
+ (!strcmp((char *) attr->ns->prefix, "xml")))
+ return(1);
+
+ if ((doc == NULL) ||
+ ((doc->intSubset == NULL) && (doc->extSubset == NULL)))
+ return(0);
+
+ if ((elem == NULL) ||
+ (elem->type != XML_ELEMENT_NODE) ||
+ (elem->name == NULL))
+ return(0);
+
fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
(xmlChar *)elem->name;
@@ -2498,6 +2528,7 @@
if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
return(1);
}
+
return(0);
}
@@ -2524,9 +2555,6 @@
if (xmlHashRemoveEntry(table, attr->id->value, xmlFreeIDTableEntry) < 0)
return(-1);
- attr->atype = 0;
- attr->id = NULL;
-
return(0);
}
@@ -2868,7 +2896,7 @@
/*If the list is empty then remove the list entry in the hash */
if (xmlListEmpty(ref_list))
- xmlHashUpdateEntry(table, ID, NULL, xmlFreeRefTableEntry);
+ xmlHashRemoveEntry(table, ID, xmlFreeRefTableEntry);
xmlFree(ID);
return(0);
}
@@ -2925,19 +2953,23 @@
xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
xmlElementTablePtr table;
xmlElementPtr cur;
- xmlChar *uqname = NULL, *prefix = NULL;
+ const xmlChar *localname;
+ xmlChar *prefix;
- if ((dtd == NULL) || (name == NULL)) return(NULL);
- if (dtd->elements == NULL)
- return(NULL);
+ if ((dtd == NULL) || (dtd->elements == NULL) ||
+ (name == NULL))
+ return(NULL);
+
table = (xmlElementTablePtr) dtd->elements;
+ if (table == NULL)
+ return(NULL);
- uqname = xmlSplitQName2(name, &prefix);
- if (uqname != NULL)
- name = uqname;
- cur = xmlHashLookup2(table, name, prefix);
- if (prefix != NULL) xmlFree(prefix);
- if (uqname != NULL) xmlFree(uqname);
+ localname = xmlSplitQName4(name, &prefix);
+ if (localname == NULL)
+ return(NULL);
+ cur = xmlHashLookup2(table, localname, prefix);
+ if (prefix != NULL)
+ xmlFree(prefix);
return(cur);
}
@@ -2986,6 +3018,7 @@
goto mem_error;
memset(cur, 0, sizeof(xmlElement));
cur->type = XML_ELEMENT_DECL;
+ cur->doc = dtd->doc;
/*
* fill the structure.
@@ -3051,23 +3084,23 @@
xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
xmlAttributeTablePtr table;
xmlAttributePtr cur;
- xmlChar *uqname = NULL, *prefix = NULL;
+ const xmlChar *localname;
+ xmlChar *prefix = NULL;
- if (dtd == NULL) return(NULL);
- if (dtd->attributes == NULL) return(NULL);
+ if ((dtd == NULL) || (dtd->attributes == NULL) ||
+ (elem == NULL) || (name == NULL))
+ return(NULL);
table = (xmlAttributeTablePtr) dtd->attributes;
if (table == NULL)
return(NULL);
- uqname = xmlSplitQName2(name, &prefix);
-
- if (uqname != NULL) {
- cur = xmlHashLookup3(table, uqname, prefix, elem);
- if (prefix != NULL) xmlFree(prefix);
- if (uqname != NULL) xmlFree(uqname);
- } else
- cur = xmlHashLookup3(table, name, NULL, elem);
+ localname = xmlSplitQName4(name, &prefix);
+ if (localname == NULL)
+ return(NULL);
+ cur = xmlHashLookup3(table, localname, prefix, elem);
+ if (prefix != NULL)
+ xmlFree(prefix);
return(cur);
}
@@ -3124,6 +3157,8 @@
* @doc: the document
* @notationName: the notation name to check
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Validate that the given name match a notation declaration.
* - [ VC: Notation Declared ]
*
@@ -3220,41 +3255,6 @@
*dst = 0;
}
-/**
- * xmlCtxtGetDtdElementDesc:
- * @ctxt: validation context
- * @dtd: a pointer to the DtD to search
- * @name: the element name
- *
- * Search the DTD for the description of this element
- *
- * returns the xmlElementPtr if found or NULL
- */
-
-static xmlElementPtr
-xmlCtxtGetDtdElementDesc(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
- const xmlChar *name) {
- xmlElementTablePtr table;
- xmlElementPtr cur;
- const xmlChar *localName;
- xmlChar *prefix;
-
- if ((dtd == NULL) || (name == NULL)) return(NULL);
- if (dtd->elements == NULL)
- return(NULL);
- table = (xmlElementTablePtr) dtd->elements;
-
- localName = xmlSplitQName4(name, &prefix);
- if (localName == NULL) {
- xmlVErrMemory(ctxt);
- return(NULL);
- }
- cur = xmlHashLookup2(table, localName, prefix);
- if (prefix != NULL)
- xmlFree(prefix);
- return(cur);
-}
-
static int
xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
@@ -3574,6 +3574,8 @@
* @doc: a document instance
* @nota: a notation definition
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Try to validate a single notation definition
* basically it does the following checks as described by the
* XML-1.0 recommendation:
@@ -3630,6 +3632,8 @@
* @type: an attribute type
* @value: an attribute value
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Validate that the given attribute value match the proper production
*
* [ VC: ID ]
@@ -3786,6 +3790,8 @@
* @value: the attribute value
* @ctxt: the validation context or NULL
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Does the validation related extra step of the normalization of attribute
* values:
*
@@ -3882,6 +3888,8 @@
* @name: the attribute name
* @value: the attribute value
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Does the validation related extra step of the normalization of attribute
* values:
*
@@ -3945,6 +3953,8 @@
* @doc: a document instance
* @attr: an attribute definition
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Try to validate a single attribute definition
* basically it does the following checks as described by the
* XML-1.0 recommendation:
@@ -3990,11 +4000,21 @@
/* One ID per Element Type */
if (attr->atype == XML_ATTRIBUTE_ID) {
+ xmlElementPtr elem = NULL;
+ const xmlChar *elemLocalName;
+ xmlChar *elemPrefix;
int nbId;
+ elemLocalName = xmlSplitQName4(attr->elem, &elemPrefix);
+ if (elemLocalName == NULL) {
+ xmlVErrMemory(ctxt);
+ return(0);
+ }
+
/* the trick is that we parse DtD as their own internal subset */
- xmlElementPtr elem = xmlCtxtGetDtdElementDesc(ctxt, doc->intSubset,
- attr->elem);
+ if (doc->intSubset != NULL)
+ elem = xmlHashLookup2(doc->intSubset->elements,
+ elemLocalName, elemPrefix);
if (elem != NULL) {
nbId = xmlScanIDAttributeDecl(ctxt, elem, 0);
} else {
@@ -4016,9 +4036,11 @@
xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
"Element %s has %d ID attribute defined in the internal subset : %s\n",
attr->elem, nbId, attr->name);
+ ret = 0;
} else if (doc->extSubset != NULL) {
int extId = 0;
- elem = xmlCtxtGetDtdElementDesc(ctxt, doc->extSubset, attr->elem);
+ elem = xmlHashLookup2(doc->extSubset->elements,
+ elemLocalName, elemPrefix);
if (elem != NULL) {
extId = xmlScanIDAttributeDecl(ctxt, elem, 0);
}
@@ -4026,12 +4048,16 @@
xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
"Element %s has %d ID attribute defined in the external subset : %s\n",
attr->elem, extId, attr->name);
+ ret = 0;
} else if (extId + nbId > 1) {
xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
"Element %s has ID attributes defined in the internal and external subset : %s\n",
attr->elem, attr->name, NULL);
+ ret = 0;
}
}
+
+ xmlFree(elemPrefix);
}
/* Validity Constraint: Enumeration */
@@ -4058,6 +4084,8 @@
* @doc: a document instance
* @elem: an element definition
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Try to validate a single element definition
* basically it does the following checks as described by the
* XML-1.0 recommendation:
@@ -4073,6 +4101,8 @@
xmlElementPtr elem) {
int ret = 1;
xmlElementPtr tst;
+ const xmlChar *localName;
+ xmlChar *prefix;
CHECK_DTD;
@@ -4136,32 +4166,47 @@
}
}
+ localName = xmlSplitQName4(elem->name, &prefix);
+ if (localName == NULL) {
+ xmlVErrMemory(ctxt);
+ return(0);
+ }
+
/* VC: Unique Element Type Declaration */
- tst = xmlCtxtGetDtdElementDesc(ctxt, doc->intSubset, elem->name);
- if ((tst != NULL ) && (tst != elem) &&
- ((tst->prefix == elem->prefix) ||
- (xmlStrEqual(tst->prefix, elem->prefix))) &&
- (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
- xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
- "Redefinition of element %s\n",
- elem->name, NULL, NULL);
- ret = 0;
+ if (doc->intSubset != NULL) {
+ tst = xmlHashLookup2(doc->intSubset->elements, localName, prefix);
+
+ if ((tst != NULL ) && (tst != elem) &&
+ ((tst->prefix == elem->prefix) ||
+ (xmlStrEqual(tst->prefix, elem->prefix))) &&
+ (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
+ xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
+ "Redefinition of element %s\n",
+ elem->name, NULL, NULL);
+ ret = 0;
+ }
}
- tst = xmlCtxtGetDtdElementDesc(ctxt, doc->extSubset, elem->name);
- if ((tst != NULL ) && (tst != elem) &&
- ((tst->prefix == elem->prefix) ||
- (xmlStrEqual(tst->prefix, elem->prefix))) &&
- (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
- xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
- "Redefinition of element %s\n",
- elem->name, NULL, NULL);
- ret = 0;
+ if (doc->extSubset != NULL) {
+ tst = xmlHashLookup2(doc->extSubset->elements, localName, prefix);
+
+ if ((tst != NULL ) && (tst != elem) &&
+ ((tst->prefix == elem->prefix) ||
+ (xmlStrEqual(tst->prefix, elem->prefix))) &&
+ (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
+ xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
+ "Redefinition of element %s\n",
+ elem->name, NULL, NULL);
+ ret = 0;
+ }
}
+
/* One ID per Element Type
* already done when registering the attribute
if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
ret = 0;
} */
+
+ xmlFree(prefix);
return(ret);
}
@@ -4173,6 +4218,8 @@
* @attr: an attribute instance
* @value: the attribute value (without entities processing)
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Try to validate a single attribute for an element
* basically it does the following checks as described by the
* XML-1.0 recommendation:
@@ -4238,6 +4285,8 @@
attr->name, elem->name, NULL);
return(0);
}
+ if (attr->atype == XML_ATTRIBUTE_ID)
+ xmlRemoveID(doc, attr);
attr->atype = attrDecl->atype;
val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
@@ -4340,6 +4389,8 @@
* @ns: an namespace declaration instance
* @value: the attribute value (without entities processing)
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Try to validate a single namespace declaration for an element
* basically it does the following checks as described by the
* XML-1.0 recommendation:
@@ -4969,7 +5020,8 @@
strcat(buf, " ...");
return;
}
- strcat(buf, (char *) cur->name);
+ if (cur->name != NULL)
+ strcat(buf, (char *) cur->name);
if (cur->next != NULL)
strcat(buf, " ");
break;
@@ -5513,6 +5565,8 @@
* @elem: an element instance
* @qname: the qualified name as appearing in the serialization
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Push a new element start on the validation stack.
*
* returns 1 if no validation problem was found or 0 otherwise
@@ -5610,6 +5664,8 @@
* @data: some character data read
* @len: the length of the data
*
+ * DEPRECATED: Internal function, don't use.
+ *
* check the CData parsed for validation in the current stack
*
* returns 1 if no validation problem was found or 0 otherwise
@@ -5683,6 +5739,8 @@
* @elem: an element instance
* @qname: the qualified name as appearing in the serialization
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Pop the element end from the validation stack.
*
* returns 1 if no validation problem was found or 0 otherwise
@@ -5737,6 +5795,8 @@
* @doc: a document instance
* @elem: an element instance
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Try to validate a single element and it's attributes,
* basically it does the following checks as described by the
* XML-1.0 recommendation:
@@ -5764,61 +5824,19 @@
if (elem == NULL) return(0);
switch (elem->type) {
- case XML_ATTRIBUTE_NODE:
- xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
- "Attribute element not expected\n", NULL, NULL ,NULL);
- return(0);
case XML_TEXT_NODE:
- if (elem->children != NULL) {
- xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
- "Text element has children !\n",
- NULL,NULL,NULL);
- return(0);
- }
- if (elem->ns != NULL) {
- xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
- "Text element has namespace !\n",
- NULL,NULL,NULL);
- return(0);
- }
- if (elem->content == NULL) {
- xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
- "Text element has no content !\n",
- NULL,NULL,NULL);
- return(0);
- }
- return(1);
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- return(1);
case XML_CDATA_SECTION_NODE:
case XML_ENTITY_REF_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
+ case XML_XINCLUDE_START:
+ case XML_XINCLUDE_END:
return(1);
- case XML_ENTITY_NODE:
- xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
- "Entity element not expected\n", NULL, NULL ,NULL);
- return(0);
- case XML_NOTATION_NODE:
- xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
- "Notation element not expected\n", NULL, NULL ,NULL);
- return(0);
- case XML_DOCUMENT_NODE:
- case XML_DOCUMENT_TYPE_NODE:
- case XML_DOCUMENT_FRAG_NODE:
- xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
- "Document element not expected\n", NULL, NULL ,NULL);
- return(0);
- case XML_HTML_DOCUMENT_NODE:
- xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
- "HTML Document not expected\n", NULL, NULL ,NULL);
- return(0);
case XML_ELEMENT_NODE:
break;
default:
xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
- "unknown element type\n", NULL, NULL ,NULL);
+ "unexpected element type\n", NULL, NULL ,NULL);
return(0);
}
@@ -5876,8 +5894,10 @@
fullname = xmlBuildQName(child->name, child->ns->prefix,
fn, 50);
- if (fullname == NULL)
+ if (fullname == NULL) {
+ xmlVErrMemory(ctxt);
return(0);
+ }
cont = elemDecl->content;
while (cont != NULL) {
if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
@@ -5941,7 +5961,8 @@
*/
child = elem->children;
while (child != NULL) {
- if (child->type == XML_TEXT_NODE) {
+ if ((child->type == XML_TEXT_NODE) &&
+ (child->content != NULL)) {
const xmlChar *content = child->content;
while (IS_BLANK_CH(*content))
@@ -5962,7 +5983,7 @@
cont = elemDecl->content;
tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
if (tmp <= 0)
- ret = tmp;
+ ret = 0;
break;
}
} /* not continuous */
@@ -6104,6 +6125,8 @@
* @ctxt: the validation context
* @doc: a document instance
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Try to validate a the root element
* basically it does the following check as described by the
* XML-1.0 recommendation:
@@ -6197,11 +6220,13 @@
attr = elem->properties;
while (attr != NULL) {
value = xmlNodeListGetString(doc, attr->children, 0);
- if (value == NULL)
+ if (value == NULL) {
xmlVErrMemory(ctxt);
- ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
- if (value != NULL)
+ ret = 0;
+ } else {
+ ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
xmlFree((char *)value);
+ }
attr= attr->next;
}
@@ -6363,6 +6388,8 @@
* @ctxt: the validation context
* @doc: a document instance
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Does the final step for the document validation once all the
* incremental validation steps have been completed
*
@@ -6439,31 +6466,42 @@
xmlDtdPtr oldExt, oldInt;
xmlNodePtr root;
- if (dtd == NULL) return(0);
- if (doc == NULL) return(0);
+ if (dtd == NULL)
+ return(0);
+ if (doc == NULL)
+ return(0);
+
oldExt = doc->extSubset;
oldInt = doc->intSubset;
doc->extSubset = dtd;
doc->intSubset = NULL;
- ret = xmlValidateRoot(ctxt, doc);
- if (ret == 0) {
- doc->extSubset = oldExt;
- doc->intSubset = oldInt;
- return(ret);
- }
if (doc->ids != NULL) {
- xmlFreeIDTable(doc->ids);
- doc->ids = NULL;
+ xmlFreeIDTable(doc->ids);
+ doc->ids = NULL;
}
if (doc->refs != NULL) {
- xmlFreeRefTable(doc->refs);
- doc->refs = NULL;
+ xmlFreeRefTable(doc->refs);
+ doc->refs = NULL;
}
- root = xmlDocGetRootElement(doc);
- ret = xmlValidateElement(ctxt, doc, root);
- ret &= xmlValidateDocumentFinal(ctxt, doc);
+
+ ret = xmlValidateRoot(ctxt, doc);
+ if (ret != 0) {
+ root = xmlDocGetRootElement(doc);
+ ret = xmlValidateElement(ctxt, doc, root);
+ ret &= xmlValidateDocumentFinal(ctxt, doc);
+ }
+
doc->extSubset = oldExt;
doc->intSubset = oldInt;
+ if (doc->ids != NULL) {
+ xmlFreeIDTable(doc->ids);
+ doc->ids = NULL;
+ }
+ if (doc->refs != NULL) {
+ xmlFreeRefTable(doc->refs);
+ doc->refs = NULL;
+ }
+
return(ret);
}
@@ -6530,6 +6568,9 @@
}
}
if (cur->atype == XML_ATTRIBUTE_NOTATION) {
+ const xmlChar *elemLocalName;
+ xmlChar *elemPrefix;
+
doc = cur->doc;
if (cur->elem == NULL) {
xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
@@ -6538,14 +6579,25 @@
return;
}
- if (doc != NULL)
- elem = xmlCtxtGetDtdElementDesc(ctxt, doc->intSubset, cur->elem);
- if ((elem == NULL) && (doc != NULL))
- elem = xmlCtxtGetDtdElementDesc(ctxt, doc->extSubset, cur->elem);
+ elemLocalName = xmlSplitQName4(cur->elem, &elemPrefix);
+ if (elemLocalName == NULL) {
+ xmlVErrMemory(ctxt);
+ return;
+ }
+
+ if ((doc != NULL) && (doc->intSubset != NULL))
+ elem = xmlHashLookup2(doc->intSubset->elements,
+ elemLocalName, elemPrefix);
+ if ((elem == NULL) && (doc != NULL) && (doc->extSubset != NULL))
+ elem = xmlHashLookup2(doc->extSubset->elements,
+ elemLocalName, elemPrefix);
if ((elem == NULL) && (cur->parent != NULL) &&
(cur->parent->type == XML_DTD_NODE))
- elem = xmlCtxtGetDtdElementDesc(ctxt, (xmlDtdPtr) cur->parent,
- cur->elem);
+ elem = xmlHashLookup2(((xmlDtdPtr) cur->parent)->elements,
+ elemLocalName, elemPrefix);
+
+ xmlFree(elemPrefix);
+
if (elem == NULL) {
xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
"attribute %s: could not find decl for element %s\n",
@@ -6566,6 +6618,8 @@
* @ctxt: the validation context
* @doc: a document instance
*
+ * DEPRECATED: Internal function, don't use.
+ *
* Does the final step for the dtds validation once all the
* subsets have been parsed
*
diff --git a/src/xmlIO.c b/src/xmlIO.c
index 96c8502..56a183a 100644
--- a/src/xmlIO.c
+++ b/src/xmlIO.c
@@ -140,7 +140,7 @@
xmlStructuredErrorFunc schannel = NULL;
xmlGenericErrorFunc channel = NULL;
void *data = NULL;
- const char *fmt, *arg;
+ const char *fmt, *arg1, *arg2;
int res;
if (code == 0) {
@@ -309,18 +309,19 @@
data = xmlGenericErrorContext;
}
- if (code == XML_IO_NETWORK_ATTEMPT) {
- fmt = "Attempt to load network entity %s";
- arg = extra;
+ if (extra != NULL) {
+ fmt = "%s: %s";
} else {
fmt = "%s";
- arg = xmlErrString(code);
}
+ arg1 = xmlErrString(code);
+ arg2 = extra;
+
res = __xmlRaiseError(schannel, channel, data, NULL, NULL,
domain, code, XML_ERR_ERROR, NULL, 0,
extra, NULL, NULL, 0, 0,
- fmt, arg);
+ fmt, arg1, arg2);
if (res < 0) {
xmlIOErrMemory();
return(XML_ERR_NO_MEMORY);
@@ -1393,7 +1394,7 @@
xmlFree(ret);
return(NULL);
}
- xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
+ xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
ret->encoder = encoder;
if (encoder != NULL) {
@@ -2451,8 +2452,10 @@
nbchars = ret >= 0 ? ret : 0;
} else {
ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
- if (ret != 0)
+ if (ret != 0) {
+ out->error = XML_ERR_NO_MEMORY;
return(-1);
+ }
if (out->writecallback)
nbchars = xmlBufUse(out->buffer);
else
@@ -2606,8 +2609,10 @@
* not the case force a flush, but make sure we stay in the loop
*/
if (chunk < 40) {
- if (xmlBufGrow(out->buffer, 100) < 0)
+ if (xmlBufGrow(out->buffer, 100) < 0) {
+ out->error = XML_ERR_NO_MEMORY;
return(-1);
+ }
oldwritten = -1;
continue;
}
@@ -2621,11 +2626,17 @@
*/
if (out->conv == NULL) {
out->conv = xmlBufCreate();
+ if (out->conv == NULL) {
+ out->error = XML_ERR_NO_MEMORY;
+ return(-1);
+ }
}
ret = escaping(xmlBufEnd(out->buffer) ,
&chunk, str, &cons);
- if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
- return(-1);
+ if (ret < 0) {
+ out->error = XML_ERR_NO_MEMORY;
+ return(-1);
+ }
xmlBufAddLen(out->buffer, chunk);
if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
@@ -2643,8 +2654,10 @@
nbchars = ret >= 0 ? ret : 0;
} else {
ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
- if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
- return(-1);
+ if (ret < 0) {
+ out->error = XML_ERR_NO_MEMORY;
+ return(-1);
+ }
xmlBufAddLen(out->buffer, chunk);
if (out->writecallback)
nbchars = xmlBufUse(out->buffer);
@@ -2676,14 +2689,17 @@
int errNo = (ret == -1) ? XML_IO_WRITE : -ret;
xmlIOErr(errNo, NULL);
out->error = errNo;
- return(ret);
+ return(-1);
}
if (out->written > INT_MAX - ret)
out->written = INT_MAX;
else
out->written += ret;
} else if (xmlBufAvail(out->buffer) < MINLEN) {
- xmlBufGrow(out->buffer, MINLEN);
+ if (xmlBufGrow(out->buffer, MINLEN) < 0) {
+ out->error = XML_ERR_NO_MEMORY;
+ return(-1);
+ }
}
written += nbchars;
} while ((len > 0) && (oldwritten != written));
@@ -2720,6 +2736,56 @@
}
/**
+ * xmlOutputBufferWriteQuotedString:
+ * @buf: output buffer
+ * @string: the string to add
+ *
+ * routine which manage and grows an output buffer. This one writes
+ * a quoted or double quoted #xmlChar string, checking first if it holds
+ * quote or double-quotes internally
+ */
+void
+xmlOutputBufferWriteQuotedString(xmlOutputBufferPtr buf,
+ const xmlChar *string) {
+ const xmlChar *cur, *base;
+
+ if ((buf == NULL) || (buf->error))
+ return;
+
+ if (xmlStrchr(string, '\"')) {
+ if (xmlStrchr(string, '\'')) {
+ xmlOutputBufferWrite(buf, 1, "\"");
+ base = cur = string;
+ while(*cur != 0){
+ if(*cur == '"'){
+ if (base != cur)
+ xmlOutputBufferWrite(buf, cur - base,
+ (const char *) base);
+ xmlOutputBufferWrite(buf, 6, """);
+ cur++;
+ base = cur;
+ }
+ else {
+ cur++;
+ }
+ }
+ if (base != cur)
+ xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+ xmlOutputBufferWrite(buf, 1, "\"");
+ }
+ else{
+ xmlOutputBufferWrite(buf, 1, "'");
+ xmlOutputBufferWriteString(buf, (const char *) string);
+ xmlOutputBufferWrite(buf, 1, "'");
+ }
+ } else {
+ xmlOutputBufferWrite(buf, 1, "\"");
+ xmlOutputBufferWriteString(buf, (const char *) string);
+ xmlOutputBufferWrite(buf, 1, "\"");
+ }
+}
+
+/**
* xmlOutputBufferFlush:
* @out: a buffered output
*
diff --git a/src/xmlreader.c b/src/xmlreader.c
index 4aaf6fc..eecca84 100644
--- a/src/xmlreader.c
+++ b/src/xmlreader.c
@@ -222,7 +222,19 @@
if (cur->children != NULL)
xmlTextReaderFreeNodeList(reader, cur->children);
- DICT_FREE(cur->name);
+ if (cur->id != NULL) {
+ /*
+ * Operating in streaming mode, attr is gonna disappear
+ */
+ cur->id->attr = NULL;
+ if (cur->id->name != NULL)
+ DICT_FREE(cur->id->name);
+ cur->id->name = cur->name;
+ cur->name = NULL;
+ } else {
+ DICT_FREE(cur->name);
+ }
+
if ((reader != NULL) && (reader->ctxt != NULL) &&
(reader->ctxt->freeAttrsNr < MAX_FREE_NODES)) {
cur->next = reader->ctxt->freeAttrs;
@@ -2866,20 +2878,17 @@
*/
const xmlChar *
xmlTextReaderConstEncoding(xmlTextReaderPtr reader) {
- xmlDocPtr doc = NULL;
- if (reader == NULL)
- return(NULL);
- if (reader->doc != NULL)
- doc = reader->doc;
- else if (reader->ctxt != NULL)
- doc = reader->ctxt->myDoc;
- if (doc == NULL)
- return(NULL);
+ const xmlChar *encoding = NULL;
- if (doc->encoding == NULL)
- return(NULL);
- else
- return(CONSTSTR(doc->encoding));
+ if (reader == NULL)
+ return(NULL);
+
+ if (reader->ctxt != NULL)
+ encoding = xmlGetActualEncoding(reader->ctxt);
+ else if (reader->doc != NULL)
+ encoding = reader->doc->encoding;
+
+ return(CONSTSTR(encoding));
}
diff --git a/src/xmlsave.c b/src/xmlsave.c
index 636432a..beb52c9 100644
--- a/src/xmlsave.c
+++ b/src/xmlsave.c
@@ -9,6 +9,7 @@
#define IN_LIBXML
#include "libxml.h"
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <libxml/xmlmemory.h>
@@ -23,6 +24,7 @@
#include "private/buf.h"
#include "private/enc.h"
#include "private/error.h"
+#include "private/io.h"
#include "private/save.h"
#ifdef LIBXML_OUTPUT_ENABLED
@@ -245,10 +247,6 @@
val = xmlGetUTF8Char(in, &len);
if (val < 0) {
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- fprintf(stderr, "xmlEscapeEntities: invalid UTF-8\n");
- abort();
-#endif
val = 0xFFFD;
in++;
} else {
@@ -395,14 +393,13 @@
while (children != NULL) {
switch (children->type) {
case XML_TEXT_NODE:
- xmlBufAttrSerializeTxtContent(buf->buffer, attr->doc,
- attr, children->content);
+ xmlBufAttrSerializeTxtContent(buf, attr->doc,
+ children->content);
break;
case XML_ENTITY_REF_NODE:
- xmlBufAdd(buf->buffer, BAD_CAST "&", 1);
- xmlBufAdd(buf->buffer, children->name,
- xmlStrlen(children->name));
- xmlBufAdd(buf->buffer, BAD_CAST ";", 1);
+ xmlOutputBufferWrite(buf, 1, "&");
+ xmlOutputBufferWriteString(buf, (const char *) children->name);
+ xmlOutputBufferWrite(buf, 1, ";");
break;
default:
/* should not happen unless we have a badly built tree */
@@ -426,14 +423,14 @@
if (nota->PublicID != NULL) {
xmlOutputBufferWrite(buf, 8, " PUBLIC ");
- xmlBufWriteQuotedString(buf->buffer, nota->PublicID);
+ xmlOutputBufferWriteQuotedString(buf, nota->PublicID);
if (nota->SystemID != NULL) {
xmlOutputBufferWrite(buf, 1, " ");
- xmlBufWriteQuotedString(buf->buffer, nota->SystemID);
+ xmlOutputBufferWriteQuotedString(buf, nota->SystemID);
}
} else {
xmlOutputBufferWrite(buf, 8, " SYSTEM ");
- xmlBufWriteQuotedString(buf->buffer, nota->SystemID);
+ xmlOutputBufferWriteQuotedString(buf, nota->SystemID);
}
xmlOutputBufferWrite(buf, 3, " >\n");
@@ -693,7 +690,7 @@
if (attr->defaultValue != NULL) {
xmlOutputBufferWrite(buf, 1, " ");
- xmlBufWriteQuotedString(buf->buffer, attr->defaultValue);
+ xmlOutputBufferWriteQuotedString(buf, attr->defaultValue);
}
xmlOutputBufferWrite(buf, 2, ">\n");
@@ -735,7 +732,7 @@
xmlOutputBufferWrite(buf, cur - base, base);
xmlOutputBufferWrite(buf, 1, "\"");
} else {
- xmlBufWriteQuotedString(buf->buffer, content);
+ xmlOutputBufferWriteQuotedString(buf, content);
}
}
@@ -761,12 +758,12 @@
(ent->etype == XML_EXTERNAL_PARAMETER_ENTITY)) {
if (ent->ExternalID != NULL) {
xmlOutputBufferWrite(buf, 7, "PUBLIC ");
- xmlBufWriteQuotedString(buf->buffer, ent->ExternalID);
+ xmlOutputBufferWriteQuotedString(buf, ent->ExternalID);
xmlOutputBufferWrite(buf, 1, " ");
} else {
xmlOutputBufferWrite(buf, 7, "SYSTEM ");
}
- xmlBufWriteQuotedString(buf->buffer, ent->SystemID);
+ xmlOutputBufferWriteQuotedString(buf, ent->SystemID);
}
if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
@@ -782,7 +779,7 @@
if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) ||
(ent->etype == XML_INTERNAL_PARAMETER_ENTITY)) {
if (ent->orig != NULL)
- xmlBufWriteQuotedString(buf->buffer, ent->orig);
+ xmlOutputBufferWriteQuotedString(buf, ent->orig);
else
xmlBufDumpEntityContent(buf, ent->content);
}
@@ -891,7 +888,7 @@
} else
xmlOutputBufferWrite(buf, 5, "xmlns");
xmlOutputBufferWrite(buf, 1, "=");
- xmlBufWriteQuotedString(buf->buffer, cur->href);
+ xmlOutputBufferWriteQuotedString(buf, cur->href);
}
}
@@ -961,12 +958,12 @@
xmlOutputBufferWriteString(buf, (const char *)dtd->name);
if (dtd->ExternalID != NULL) {
xmlOutputBufferWrite(buf, 8, " PUBLIC ");
- xmlBufWriteQuotedString(buf->buffer, dtd->ExternalID);
+ xmlOutputBufferWriteQuotedString(buf, dtd->ExternalID);
xmlOutputBufferWrite(buf, 1, " ");
- xmlBufWriteQuotedString(buf->buffer, dtd->SystemID);
+ xmlOutputBufferWriteQuotedString(buf, dtd->SystemID);
} else if (dtd->SystemID != NULL) {
xmlOutputBufferWrite(buf, 8, " SYSTEM ");
- xmlBufWriteQuotedString(buf->buffer, dtd->SystemID);
+ xmlOutputBufferWriteQuotedString(buf, dtd->SystemID);
}
if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
(dtd->attributes == NULL) && (dtd->notations == NULL) &&
@@ -1460,12 +1457,12 @@
if ((ctxt->options & XML_SAVE_NO_DECL) == 0) {
xmlOutputBufferWrite(buf, 14, "<?xml version=");
if (cur->version != NULL)
- xmlBufWriteQuotedString(buf->buffer, cur->version);
+ xmlOutputBufferWriteQuotedString(buf, cur->version);
else
xmlOutputBufferWrite(buf, 5, "\"1.0\"");
if (encoding != NULL) {
xmlOutputBufferWrite(buf, 10, " encoding=");
- xmlBufWriteQuotedString(buf->buffer, (xmlChar *) encoding);
+ xmlOutputBufferWriteQuotedString(buf, (xmlChar *) encoding);
}
switch (cur->standalone) {
case 0:
@@ -1545,7 +1542,7 @@
return(0);
if (node->children != NULL)
return(0);
- switch (node->name[0]) {
+ switch (node->name ? node->name[0] : 0) {
case 'a':
if (xmlStrEqual(node->name, BAD_CAST "area"))
return(1);
@@ -2170,12 +2167,16 @@
int
xmlSaveNotationDecl(xmlSaveCtxtPtr ctxt, xmlNotationPtr cur) {
+ if (ctxt == NULL)
+ return(-1);
xmlBufDumpNotationDecl(ctxt->buf, cur);
return(0);
}
int
xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur) {
+ if (ctxt == NULL)
+ return(-1);
xmlBufDumpNotationTable(ctxt->buf, cur);
return(0);
}
@@ -2281,7 +2282,7 @@
/**
* xmlBufAttrSerializeTxtContent:
- * @buf: and xmlBufPtr output
+ * @buf: output buffer
* @doc: the document
* @attr: the attribute node
* @string: the text content
@@ -2289,56 +2290,55 @@
* Serialize text attribute values to an xmlBufPtr
*/
void
-xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc,
- xmlAttrPtr attr ATTRIBUTE_UNUSED,
- const xmlChar * string)
+xmlBufAttrSerializeTxtContent(xmlOutputBufferPtr buf, xmlDocPtr doc,
+ const xmlChar *string)
{
- xmlChar *base, *cur;
+ const xmlChar *base, *cur;
if (string == NULL)
return;
- base = cur = (xmlChar *) string;
+ base = cur = string;
while (*cur != 0) {
if (*cur == '\n') {
if (base != cur)
- xmlBufAdd(buf, base, cur - base);
- xmlBufAdd(buf, BAD_CAST " ", 5);
+ xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+ xmlOutputBufferWrite(buf, 5, " ");
cur++;
base = cur;
} else if (*cur == '\r') {
if (base != cur)
- xmlBufAdd(buf, base, cur - base);
- xmlBufAdd(buf, BAD_CAST " ", 5);
+ xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+ xmlOutputBufferWrite(buf, 5, " ");
cur++;
base = cur;
} else if (*cur == '\t') {
if (base != cur)
- xmlBufAdd(buf, base, cur - base);
- xmlBufAdd(buf, BAD_CAST "	", 4);
+ xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+ xmlOutputBufferWrite(buf, 4, "	");
cur++;
base = cur;
} else if (*cur == '"') {
if (base != cur)
- xmlBufAdd(buf, base, cur - base);
- xmlBufAdd(buf, BAD_CAST """, 6);
+ xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+ xmlOutputBufferWrite(buf, 6, """);
cur++;
base = cur;
} else if (*cur == '<') {
if (base != cur)
- xmlBufAdd(buf, base, cur - base);
- xmlBufAdd(buf, BAD_CAST "<", 4);
+ xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+ xmlOutputBufferWrite(buf, 4, "<");
cur++;
base = cur;
} else if (*cur == '>') {
if (base != cur)
- xmlBufAdd(buf, base, cur - base);
- xmlBufAdd(buf, BAD_CAST ">", 4);
+ xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+ xmlOutputBufferWrite(buf, 4, ">");
cur++;
base = cur;
} else if (*cur == '&') {
if (base != cur)
- xmlBufAdd(buf, base, cur - base);
- xmlBufAdd(buf, BAD_CAST "&", 5);
+ xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+ xmlOutputBufferWrite(buf, 5, "&");
cur++;
base = cur;
} else if ((*cur >= 0x80) && (cur[1] != 0) &&
@@ -2350,14 +2350,10 @@
int val = 0, l = 4;
if (base != cur)
- xmlBufAdd(buf, base, cur - base);
+ xmlOutputBufferWrite(buf, cur - base, (const char *) base);
val = xmlGetUTF8Char(cur, &l);
if (val < 0) {
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- fprintf(stderr, "xmlEscapeEntities: invalid UTF-8\n");
- abort();
-#endif
val = 0xFFFD;
cur++;
} else {
@@ -2371,14 +2367,14 @@
* as a char ref
*/
xmlSerializeHexCharRef(tmp, val);
- xmlBufAdd(buf, (xmlChar *) tmp, -1);
+ xmlOutputBufferWriteString(buf, (const char *) tmp);
base = cur;
} else {
cur++;
}
}
if (base != cur)
- xmlBufAdd(buf, base, cur - base);
+ xmlOutputBufferWrite(buf, cur - base, (const char *) base);
}
/**
@@ -2392,17 +2388,18 @@
*/
void
xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc,
- xmlAttrPtr attr, const xmlChar * string)
+ xmlAttrPtr attr ATTRIBUTE_UNUSED,
+ const xmlChar *string)
{
- xmlBufPtr buffer;
+ xmlOutputBufferPtr out;
if ((buf == NULL) || (string == NULL))
return;
- buffer = xmlBufFromBuffer(buf);
- if (buffer == NULL)
- return;
- xmlBufAttrSerializeTxtContent(buffer, doc, attr, string);
- xmlBufBackToBuffer(buffer);
+ out = xmlOutputBufferCreateBuffer(buf, NULL);
+ xmlBufAttrSerializeTxtContent(out, doc, string);
+ if ((out == NULL) || (out->error))
+ xmlFree(xmlBufferDetach(buf));
+ xmlOutputBufferClose(out);
}
/**
@@ -2430,6 +2427,10 @@
if ((buf == NULL) || (cur == NULL))
return(-1);
+ if (level < 0)
+ level = 0;
+ else if (level > 100)
+ level = 100;
buffer = xmlBufFromBuffer(buf);
if (buffer == NULL)
return(-1);
@@ -2461,22 +2462,22 @@
int format)
{
size_t use;
- int ret;
+ size_t ret;
xmlOutputBufferPtr outbuf;
int oldalloc;
xmlInitParser();
if (cur == NULL) {
- return (-1);
+ return ((size_t) -1);
}
if (buf == NULL) {
- return (-1);
+ return ((size_t) -1);
}
outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
if (outbuf == NULL) {
xmlSaveErrMemory(NULL);
- return (-1);
+ return ((size_t) -1);
}
memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
outbuf->buffer = buf;
@@ -2491,8 +2492,11 @@
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
xmlBufSetAllocationScheme(buf, oldalloc);
+ if (outbuf->error)
+ ret = (size_t) -1;
+ else
+ ret = xmlBufUse(buf) - use;
xmlFree(outbuf);
- ret = xmlBufUse(buf) - use;
return (ret);
}
@@ -2562,6 +2566,11 @@
if ((buf == NULL) || (cur == NULL)) return;
+ if (level < 0)
+ level = 0;
+ else if (level > 100)
+ level = 100;
+
if (encoding == NULL)
encoding = "UTF-8";
@@ -2611,8 +2620,6 @@
int dummy = 0;
xmlOutputBufferPtr out_buff = NULL;
xmlCharEncodingHandlerPtr conv_hdlr = NULL;
- xmlChar *content;
- int len;
if (doc_txt_len == NULL) {
doc_txt_len = &dummy; /* Continue, caller just won't get length */
@@ -2664,29 +2671,18 @@
ctxt.options |= XML_SAVE_AS_XML;
xmlDocContentDumpOutput(&ctxt, out_doc);
xmlOutputBufferFlush(out_buff);
- if (out_buff->conv != NULL) {
- if (xmlBufContent(out_buff->buffer) == NULL)
- goto error;
- content = xmlBufContent(out_buff->conv);
- len = xmlBufUse(out_buff->conv);
- } else {
- content = xmlBufContent(out_buff->buffer);
- len = xmlBufUse(out_buff->buffer);
+
+ if (!out_buff->error) {
+ if (out_buff->conv != NULL) {
+ *doc_txt_len = xmlBufUse(out_buff->conv);
+ *doc_txt_ptr = xmlBufDetach(out_buff->conv);
+ } else {
+ *doc_txt_len = xmlBufUse(out_buff->buffer);
+ *doc_txt_ptr = xmlBufDetach(out_buff->buffer);
+ }
}
- if (content == NULL)
- goto error;
- *doc_txt_ptr = xmlStrndup(content, len);
- if (*doc_txt_ptr == NULL)
- goto error;
- *doc_txt_len = len;
- xmlOutputBufferClose(out_buff);
- return;
-
-error:
- xmlSaveErrMemory(NULL);
xmlOutputBufferClose(out_buff);
- return;
}
/**
diff --git a/src/xmlstring.c b/src/xmlstring.c
index e30c084..8b08802 100644
--- a/src/xmlstring.c
+++ b/src/xmlstring.c
@@ -499,10 +499,10 @@
if (len < 0)
return(NULL);
}
- if ((str2 == NULL) || (len == 0))
- return(xmlStrdup(str1));
if (str1 == NULL)
return(xmlStrndup(str2, len));
+ if ((str2 == NULL) || (len == 0))
+ return(xmlStrdup(str1));
size = xmlStrlen(str1);
if ((size < 0) || (size > INT_MAX - len))
diff --git a/src/xmlwriter.c b/src/xmlwriter.c
index a63a69f..f648dc0 100644
--- a/src/xmlwriter.c
+++ b/src/xmlwriter.c
@@ -1496,8 +1496,8 @@
break;
case XML_TEXTWRITER_ATTRIBUTE:
buf = NULL;
- xmlBufAttrSerializeTxtContent(writer->out->buffer,
- writer->doc, NULL, content);
+ xmlBufAttrSerializeTxtContent(writer->out, writer->doc,
+ content);
break;
default:
break;
diff --git a/src/xpath.c b/src/xpath.c
index 3bff0d5..d173186 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -4260,10 +4260,8 @@
if (prefix == NULL)
return(NULL);
-#ifdef XML_XML_NAMESPACE
if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
return(XML_XML_NAMESPACE);
-#endif
if (ctxt->namespaces != NULL) {
int i;
@@ -8318,7 +8316,7 @@
if (ctxt->error != 0)
goto error;
- target = xmlBufCreate();
+ target = xmlBufCreateSize(64);
if (target == NULL) {
xmlXPathPErrMemory(ctxt);
goto error;
@@ -13408,7 +13406,7 @@
CAST_TO_STRING;
str = valuePop(ctxt);
- target = xmlBufCreate();
+ target = xmlBufCreateSize(64);
escape[0] = '%';
escape[3] = 0;