ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

tree.c
Go to the documentation of this file.
00001 /*
00002  * tree.c : implementation of access function for an XML tree.
00003  *
00004  * References:
00005  *   XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
00006  *
00007  * See Copyright for the status of this software.
00008  *
00009  * daniel@veillard.com
00010  *
00011  */
00012 
00013 #define IN_LIBXML
00014 #include "libxml.h"
00015 
00016 #include <string.h> /* for memset() only ! */
00017 #include <limits.h>
00018 #ifdef HAVE_CTYPE_H
00019 #include <ctype.h>
00020 #endif
00021 #ifdef HAVE_STDLIB_H
00022 #include <stdlib.h>
00023 #endif
00024 #ifdef HAVE_ZLIB_H
00025 #include <zlib.h>
00026 #endif
00027 
00028 #include <libxml/xmlmemory.h>
00029 #include <libxml/tree.h>
00030 #include <libxml/parser.h>
00031 #include <libxml/uri.h>
00032 #include <libxml/entities.h>
00033 #include <libxml/valid.h>
00034 #include <libxml/xmlerror.h>
00035 #include <libxml/parserInternals.h>
00036 #include <libxml/globals.h>
00037 #ifdef LIBXML_HTML_ENABLED
00038 #include <libxml/HTMLtree.h>
00039 #endif
00040 #ifdef LIBXML_DEBUG_ENABLED
00041 #include <libxml/debugXML.h>
00042 #endif
00043 
00044 int __xmlRegisterCallbacks = 0;
00045 
00046 /************************************************************************
00047  *                                  *
00048  *      Forward declarations                    *
00049  *                                  *
00050  ************************************************************************/
00051 
00052 static xmlNsPtr
00053 xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
00054 
00055 static xmlChar* xmlGetPropNodeValueInternal(xmlAttrPtr prop);
00056 
00057 /************************************************************************
00058  *                                  *
00059  *      Tree memory error handler               *
00060  *                                  *
00061  ************************************************************************/
00068 static void
00069 xmlTreeErrMemory(const char *extra)
00070 {
00071     __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
00072 }
00073 
00081 static void
00082 xmlTreeErr(int code, xmlNodePtr node, const char *extra)
00083 {
00084     const char *msg = NULL;
00085 
00086     switch(code) {
00087         case XML_TREE_INVALID_HEX:
00088         msg = "invalid hexadecimal character value\n";
00089         break;
00090     case XML_TREE_INVALID_DEC:
00091         msg = "invalid decimal character value\n";
00092         break;
00093     case XML_TREE_UNTERMINATED_ENTITY:
00094         msg = "unterminated entity reference %15s\n";
00095         break;
00096     case XML_TREE_NOT_UTF8:
00097         msg = "string is not in UTF-8\n";
00098         break;
00099     default:
00100         msg = "unexpected error number\n";
00101     }
00102     __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
00103 }
00104 
00105 /************************************************************************
00106  *                                  *
00107  *      A few static variables and macros           *
00108  *                                  *
00109  ************************************************************************/
00110 /* #undef xmlStringText */
00111 const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
00112 /* #undef xmlStringTextNoenc */
00113 const xmlChar xmlStringTextNoenc[] =
00114               { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
00115 /* #undef xmlStringComment */
00116 const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
00117 
00118 static int xmlCompressMode = 0;
00119 static int xmlCheckDTD = 1;
00120 
00121 #define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) {      \
00122     xmlNodePtr ulccur = (n)->children;                  \
00123     if (ulccur == NULL) {                       \
00124         (n)->last = NULL;                       \
00125     } else {                                \
00126         while (ulccur->next != NULL) {                  \
00127         ulccur->parent = (n);                   \
00128         ulccur = ulccur->next;                  \
00129     }                               \
00130     ulccur->parent = (n);                       \
00131     (n)->last = ulccur;                     \
00132 }}
00133 
00134 #define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
00135   (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
00136 
00137 /* #define DEBUG_BUFFER */
00138 /* #define DEBUG_TREE */
00139 
00140 /************************************************************************
00141  *                                  *
00142  *      Functions to move to entities.c once the        *
00143  *      API freeze is smoothen and they can be made public. *
00144  *                                  *
00145  ************************************************************************/
00146 #include <libxml/hash.h>
00147 
00148 #ifdef LIBXML_TREE_ENABLED
00149 
00159 static xmlEntityPtr
00160 xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
00161     xmlEntitiesTablePtr table;
00162 
00163     if((dtd != NULL) && (dtd->entities != NULL)) {
00164     table = (xmlEntitiesTablePtr) dtd->entities;
00165     return((xmlEntityPtr) xmlHashLookup(table, name));
00166     /* return(xmlGetEntityFromTable(table, name)); */
00167     }
00168     return(NULL);
00169 }
00180 static xmlEntityPtr
00181 xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
00182     xmlEntitiesTablePtr table;
00183 
00184     if ((dtd != NULL) && (dtd->pentities != NULL)) {
00185     table = (xmlEntitiesTablePtr) dtd->pentities;
00186     return((xmlEntityPtr) xmlHashLookup(table, name));
00187     /* return(xmlGetEntityFromTable(table, name)); */
00188     }
00189     return(NULL);
00190 }
00191 #endif /* LIBXML_TREE_ENABLED */
00192 
00193 /************************************************************************
00194  *                                  *
00195  *          QName handling helper               *
00196  *                                  *
00197  ************************************************************************/
00198 
00213 xmlChar *
00214 xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
00215           xmlChar *memory, int len) {
00216     int lenn, lenp;
00217     xmlChar *ret;
00218 
00219     if (ncname == NULL) return(NULL);
00220     if (prefix == NULL) return((xmlChar *) ncname);
00221 
00222     lenn = strlen((char *) ncname);
00223     lenp = strlen((char *) prefix);
00224 
00225     if ((memory == NULL) || (len < lenn + lenp + 2)) {
00226     ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
00227     if (ret == NULL) {
00228         xmlTreeErrMemory("building QName");
00229         return(NULL);
00230     }
00231     } else {
00232     ret = memory;
00233     }
00234     memcpy(&ret[0], prefix, lenp);
00235     ret[lenp] = ':';
00236     memcpy(&ret[lenp + 1], ncname, lenn);
00237     ret[lenn + lenp + 1] = 0;
00238     return(ret);
00239 }
00240 
00258 xmlChar *
00259 xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
00260     int len = 0;
00261     xmlChar *ret = NULL;
00262 
00263     if (prefix == NULL) return(NULL);
00264     *prefix = NULL;
00265     if (name == NULL) return(NULL);
00266 
00267 #ifndef XML_XML_NAMESPACE
00268     /* xml: prefix is not really a namespace */
00269     if ((name[0] == 'x') && (name[1] == 'm') &&
00270         (name[2] == 'l') && (name[3] == ':'))
00271     return(NULL);
00272 #endif
00273 
00274     /* nasty but valid */
00275     if (name[0] == ':')
00276     return(NULL);
00277 
00278     /*
00279      * we are not trying to validate but just to cut, and yes it will
00280      * work even if this is as set of UTF-8 encoded chars
00281      */
00282     while ((name[len] != 0) && (name[len] != ':'))
00283     len++;
00284 
00285     if (name[len] == 0)
00286     return(NULL);
00287 
00288     *prefix = xmlStrndup(name, len);
00289     if (*prefix == NULL) {
00290     xmlTreeErrMemory("QName split");
00291     return(NULL);
00292     }
00293     ret = xmlStrdup(&name[len + 1]);
00294     if (ret == NULL) {
00295     xmlTreeErrMemory("QName split");
00296     if (*prefix != NULL) {
00297         xmlFree(*prefix);
00298         *prefix = NULL;
00299     }
00300     return(NULL);
00301     }
00302 
00303     return(ret);
00304 }
00305 
00318 const xmlChar *
00319 xmlSplitQName3(const xmlChar *name, int *len) {
00320     int l = 0;
00321 
00322     if (name == NULL) return(NULL);
00323     if (len == NULL) return(NULL);
00324 
00325     /* nasty but valid */
00326     if (name[0] == ':')
00327     return(NULL);
00328 
00329     /*
00330      * we are not trying to validate but just to cut, and yes it will
00331      * work even if this is as set of UTF-8 encoded chars
00332      */
00333     while ((name[l] != 0) && (name[l] != ':'))
00334     l++;
00335 
00336     if (name[l] == 0)
00337     return(NULL);
00338 
00339     *len = l;
00340 
00341     return(&name[l+1]);
00342 }
00343 
00344 /************************************************************************
00345  *                                  *
00346  *      Check Name, NCName and QName strings            *
00347  *                                  *
00348  ************************************************************************/
00349 
00350 #define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
00351 
00352 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED)
00353 
00363 int
00364 xmlValidateNCName(const xmlChar *value, int space) {
00365     const xmlChar *cur = value;
00366     int c,l;
00367 
00368     if (value == NULL)
00369         return(-1);
00370 
00371     /*
00372      * First quick algorithm for ASCII range
00373      */
00374     if (space)
00375     while (IS_BLANK_CH(*cur)) cur++;
00376     if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
00377     (*cur == '_'))
00378     cur++;
00379     else
00380     goto try_complex;
00381     while (((*cur >= 'a') && (*cur <= 'z')) ||
00382        ((*cur >= 'A') && (*cur <= 'Z')) ||
00383        ((*cur >= '0') && (*cur <= '9')) ||
00384        (*cur == '_') || (*cur == '-') || (*cur == '.'))
00385     cur++;
00386     if (space)
00387     while (IS_BLANK_CH(*cur)) cur++;
00388     if (*cur == 0)
00389     return(0);
00390 
00391 try_complex:
00392     /*
00393      * Second check for chars outside the ASCII range
00394      */
00395     cur = value;
00396     c = CUR_SCHAR(cur, l);
00397     if (space) {
00398     while (IS_BLANK(c)) {
00399         cur += l;
00400         c = CUR_SCHAR(cur, l);
00401     }
00402     }
00403     if ((!IS_LETTER(c)) && (c != '_'))
00404     return(1);
00405     cur += l;
00406     c = CUR_SCHAR(cur, l);
00407     while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
00408        (c == '-') || (c == '_') || IS_COMBINING(c) ||
00409        IS_EXTENDER(c)) {
00410     cur += l;
00411     c = CUR_SCHAR(cur, l);
00412     }
00413     if (space) {
00414     while (IS_BLANK(c)) {
00415         cur += l;
00416         c = CUR_SCHAR(cur, l);
00417     }
00418     }
00419     if (c != 0)
00420     return(1);
00421 
00422     return(0);
00423 }
00424 #endif
00425 
00426 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
00427 
00437 int
00438 xmlValidateQName(const xmlChar *value, int space) {
00439     const xmlChar *cur = value;
00440     int c,l;
00441 
00442     if (value == NULL)
00443         return(-1);
00444     /*
00445      * First quick algorithm for ASCII range
00446      */
00447     if (space)
00448     while (IS_BLANK_CH(*cur)) cur++;
00449     if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
00450     (*cur == '_'))
00451     cur++;
00452     else
00453     goto try_complex;
00454     while (((*cur >= 'a') && (*cur <= 'z')) ||
00455        ((*cur >= 'A') && (*cur <= 'Z')) ||
00456        ((*cur >= '0') && (*cur <= '9')) ||
00457        (*cur == '_') || (*cur == '-') || (*cur == '.'))
00458     cur++;
00459     if (*cur == ':') {
00460     cur++;
00461     if (((*cur >= 'a') && (*cur <= 'z')) ||
00462         ((*cur >= 'A') && (*cur <= 'Z')) ||
00463         (*cur == '_'))
00464         cur++;
00465     else
00466         goto try_complex;
00467     while (((*cur >= 'a') && (*cur <= 'z')) ||
00468            ((*cur >= 'A') && (*cur <= 'Z')) ||
00469            ((*cur >= '0') && (*cur <= '9')) ||
00470            (*cur == '_') || (*cur == '-') || (*cur == '.'))
00471         cur++;
00472     }
00473     if (space)
00474     while (IS_BLANK_CH(*cur)) cur++;
00475     if (*cur == 0)
00476     return(0);
00477 
00478 try_complex:
00479     /*
00480      * Second check for chars outside the ASCII range
00481      */
00482     cur = value;
00483     c = CUR_SCHAR(cur, l);
00484     if (space) {
00485     while (IS_BLANK(c)) {
00486         cur += l;
00487         c = CUR_SCHAR(cur, l);
00488     }
00489     }
00490     if ((!IS_LETTER(c)) && (c != '_'))
00491     return(1);
00492     cur += l;
00493     c = CUR_SCHAR(cur, l);
00494     while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
00495        (c == '-') || (c == '_') || IS_COMBINING(c) ||
00496        IS_EXTENDER(c)) {
00497     cur += l;
00498     c = CUR_SCHAR(cur, l);
00499     }
00500     if (c == ':') {
00501     cur += l;
00502     c = CUR_SCHAR(cur, l);
00503     if ((!IS_LETTER(c)) && (c != '_'))
00504         return(1);
00505     cur += l;
00506     c = CUR_SCHAR(cur, l);
00507     while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
00508            (c == '-') || (c == '_') || IS_COMBINING(c) ||
00509            IS_EXTENDER(c)) {
00510         cur += l;
00511         c = CUR_SCHAR(cur, l);
00512     }
00513     }
00514     if (space) {
00515     while (IS_BLANK(c)) {
00516         cur += l;
00517         c = CUR_SCHAR(cur, l);
00518     }
00519     }
00520     if (c != 0)
00521     return(1);
00522     return(0);
00523 }
00524 
00535 int
00536 xmlValidateName(const xmlChar *value, int space) {
00537     const xmlChar *cur = value;
00538     int c,l;
00539 
00540     if (value == NULL)
00541         return(-1);
00542     /*
00543      * First quick algorithm for ASCII range
00544      */
00545     if (space)
00546     while (IS_BLANK_CH(*cur)) cur++;
00547     if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
00548     (*cur == '_') || (*cur == ':'))
00549     cur++;
00550     else
00551     goto try_complex;
00552     while (((*cur >= 'a') && (*cur <= 'z')) ||
00553        ((*cur >= 'A') && (*cur <= 'Z')) ||
00554        ((*cur >= '0') && (*cur <= '9')) ||
00555        (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
00556     cur++;
00557     if (space)
00558     while (IS_BLANK_CH(*cur)) cur++;
00559     if (*cur == 0)
00560     return(0);
00561 
00562 try_complex:
00563     /*
00564      * Second check for chars outside the ASCII range
00565      */
00566     cur = value;
00567     c = CUR_SCHAR(cur, l);
00568     if (space) {
00569     while (IS_BLANK(c)) {
00570         cur += l;
00571         c = CUR_SCHAR(cur, l);
00572     }
00573     }
00574     if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
00575     return(1);
00576     cur += l;
00577     c = CUR_SCHAR(cur, l);
00578     while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
00579        (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
00580     cur += l;
00581     c = CUR_SCHAR(cur, l);
00582     }
00583     if (space) {
00584     while (IS_BLANK(c)) {
00585         cur += l;
00586         c = CUR_SCHAR(cur, l);
00587     }
00588     }
00589     if (c != 0)
00590     return(1);
00591     return(0);
00592 }
00593 
00604 int
00605 xmlValidateNMToken(const xmlChar *value, int space) {
00606     const xmlChar *cur = value;
00607     int c,l;
00608 
00609     if (value == NULL)
00610         return(-1);
00611     /*
00612      * First quick algorithm for ASCII range
00613      */
00614     if (space)
00615     while (IS_BLANK_CH(*cur)) cur++;
00616     if (((*cur >= 'a') && (*cur <= 'z')) ||
00617         ((*cur >= 'A') && (*cur <= 'Z')) ||
00618         ((*cur >= '0') && (*cur <= '9')) ||
00619         (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
00620     cur++;
00621     else
00622     goto try_complex;
00623     while (((*cur >= 'a') && (*cur <= 'z')) ||
00624        ((*cur >= 'A') && (*cur <= 'Z')) ||
00625        ((*cur >= '0') && (*cur <= '9')) ||
00626        (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
00627     cur++;
00628     if (space)
00629     while (IS_BLANK_CH(*cur)) cur++;
00630     if (*cur == 0)
00631     return(0);
00632 
00633 try_complex:
00634     /*
00635      * Second check for chars outside the ASCII range
00636      */
00637     cur = value;
00638     c = CUR_SCHAR(cur, l);
00639     if (space) {
00640     while (IS_BLANK(c)) {
00641         cur += l;
00642         c = CUR_SCHAR(cur, l);
00643     }
00644     }
00645     if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
00646         (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
00647     return(1);
00648     cur += l;
00649     c = CUR_SCHAR(cur, l);
00650     while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
00651        (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
00652     cur += l;
00653     c = CUR_SCHAR(cur, l);
00654     }
00655     if (space) {
00656     while (IS_BLANK(c)) {
00657         cur += l;
00658         c = CUR_SCHAR(cur, l);
00659     }
00660     }
00661     if (c != 0)
00662     return(1);
00663     return(0);
00664 }
00665 #endif /* LIBXML_TREE_ENABLED */
00666 
00667 /************************************************************************
00668  *                                  *
00669  *      Allocation and deallocation of basic structures     *
00670  *                                  *
00671  ************************************************************************/
00672 
00682 void
00683 xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
00684     if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
00685         (scheme == XML_BUFFER_ALLOC_DOUBLEIT))
00686     xmlBufferAllocScheme = scheme;
00687 }
00688 
00699 xmlBufferAllocationScheme
00700 xmlGetBufferAllocationScheme(void) {
00701     return(xmlBufferAllocScheme);
00702 }
00703 
00717 xmlNsPtr
00718 xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
00719     xmlNsPtr cur;
00720 
00721     if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
00722     return(NULL);
00723 
00724     if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
00725         /* xml namespace is predefined, no need to add it */
00726         if (xmlStrEqual(href, XML_XML_NAMESPACE))
00727             return(NULL);
00728 
00729         /*
00730          * Problem, this is an attempt to bind xml prefix to a wrong
00731          * namespace, which breaks
00732          * Namespace constraint: Reserved Prefixes and Namespace Names
00733          * from XML namespace. But documents authors may not care in
00734          * their context so let's proceed.
00735          */
00736     }
00737 
00738     /*
00739      * Allocate a new Namespace and fill the fields.
00740      */
00741     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
00742     if (cur == NULL) {
00743     xmlTreeErrMemory("building namespace");
00744     return(NULL);
00745     }
00746     memset(cur, 0, sizeof(xmlNs));
00747     cur->type = XML_LOCAL_NAMESPACE;
00748 
00749     if (href != NULL)
00750     cur->href = xmlStrdup(href);
00751     if (prefix != NULL)
00752     cur->prefix = xmlStrdup(prefix);
00753 
00754     /*
00755      * Add it at the end to preserve parsing order ...
00756      * and checks for existing use of the prefix
00757      */
00758     if (node != NULL) {
00759     if (node->nsDef == NULL) {
00760         node->nsDef = cur;
00761     } else {
00762         xmlNsPtr prev = node->nsDef;
00763 
00764         if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
00765         (xmlStrEqual(prev->prefix, cur->prefix))) {
00766         xmlFreeNs(cur);
00767         return(NULL);
00768         }
00769         while (prev->next != NULL) {
00770             prev = prev->next;
00771         if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
00772             (xmlStrEqual(prev->prefix, cur->prefix))) {
00773             xmlFreeNs(cur);
00774             return(NULL);
00775         }
00776         }
00777         prev->next = cur;
00778     }
00779     }
00780     return(cur);
00781 }
00782 
00790 void
00791 xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
00792     if (node == NULL) {
00793 #ifdef DEBUG_TREE
00794         xmlGenericError(xmlGenericErrorContext,
00795         "xmlSetNs: node == NULL\n");
00796 #endif
00797     return;
00798     }
00799     node->ns = ns;
00800 }
00801 
00808 void
00809 xmlFreeNs(xmlNsPtr cur) {
00810     if (cur == NULL) {
00811 #ifdef DEBUG_TREE
00812         xmlGenericError(xmlGenericErrorContext,
00813         "xmlFreeNs : ns == NULL\n");
00814 #endif
00815     return;
00816     }
00817     if (cur->href != NULL) xmlFree((char *) cur->href);
00818     if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
00819     xmlFree(cur);
00820 }
00821 
00828 void
00829 xmlFreeNsList(xmlNsPtr cur) {
00830     xmlNsPtr next;
00831     if (cur == NULL) {
00832 #ifdef DEBUG_TREE
00833         xmlGenericError(xmlGenericErrorContext,
00834         "xmlFreeNsList : ns == NULL\n");
00835 #endif
00836     return;
00837     }
00838     while (cur != NULL) {
00839         next = cur->next;
00840         xmlFreeNs(cur);
00841     cur = next;
00842     }
00843 }
00844 
00857 xmlDtdPtr
00858 xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
00859                     const xmlChar *ExternalID, const xmlChar *SystemID) {
00860     xmlDtdPtr cur;
00861 
00862     if ((doc != NULL) && (doc->extSubset != NULL)) {
00863 #ifdef DEBUG_TREE
00864         xmlGenericError(xmlGenericErrorContext,
00865         "xmlNewDtd(%s): document %s already have a DTD %s\n",
00866         /* !!! */ (char *) name, doc->name,
00867         /* !!! */ (char *)doc->extSubset->name);
00868 #endif
00869     return(NULL);
00870     }
00871 
00872     /*
00873      * Allocate a new DTD and fill the fields.
00874      */
00875     cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
00876     if (cur == NULL) {
00877     xmlTreeErrMemory("building DTD");
00878     return(NULL);
00879     }
00880     memset(cur, 0 , sizeof(xmlDtd));
00881     cur->type = XML_DTD_NODE;
00882 
00883     if (name != NULL)
00884     cur->name = xmlStrdup(name);
00885     if (ExternalID != NULL)
00886     cur->ExternalID = xmlStrdup(ExternalID);
00887     if (SystemID != NULL)
00888     cur->SystemID = xmlStrdup(SystemID);
00889     if (doc != NULL)
00890     doc->extSubset = cur;
00891     cur->doc = doc;
00892 
00893     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
00894     xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
00895     return(cur);
00896 }
00897 
00906 xmlDtdPtr
00907 xmlGetIntSubset(xmlDocPtr doc) {
00908     xmlNodePtr cur;
00909 
00910     if (doc == NULL)
00911     return(NULL);
00912     cur = doc->children;
00913     while (cur != NULL) {
00914     if (cur->type == XML_DTD_NODE)
00915         return((xmlDtdPtr) cur);
00916     cur = cur->next;
00917     }
00918     return((xmlDtdPtr) doc->intSubset);
00919 }
00920 
00931 xmlDtdPtr
00932 xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
00933                    const xmlChar *ExternalID, const xmlChar *SystemID) {
00934     xmlDtdPtr cur;
00935 
00936     if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
00937 #ifdef DEBUG_TREE
00938         xmlGenericError(xmlGenericErrorContext,
00939 
00940      "xmlCreateIntSubset(): document %s already have an internal subset\n",
00941         doc->name);
00942 #endif
00943     return(NULL);
00944     }
00945 
00946     /*
00947      * Allocate a new DTD and fill the fields.
00948      */
00949     cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
00950     if (cur == NULL) {
00951     xmlTreeErrMemory("building internal subset");
00952     return(NULL);
00953     }
00954     memset(cur, 0, sizeof(xmlDtd));
00955     cur->type = XML_DTD_NODE;
00956 
00957     if (name != NULL) {
00958     cur->name = xmlStrdup(name);
00959     if (cur->name == NULL) {
00960         xmlTreeErrMemory("building internal subset");
00961         xmlFree(cur);
00962         return(NULL);
00963     }
00964     }
00965     if (ExternalID != NULL) {
00966     cur->ExternalID = xmlStrdup(ExternalID);
00967     if (cur->ExternalID  == NULL) {
00968         xmlTreeErrMemory("building internal subset");
00969         if (cur->name != NULL)
00970             xmlFree((char *)cur->name);
00971         xmlFree(cur);
00972         return(NULL);
00973     }
00974     }
00975     if (SystemID != NULL) {
00976     cur->SystemID = xmlStrdup(SystemID);
00977     if (cur->SystemID == NULL) {
00978         xmlTreeErrMemory("building internal subset");
00979         if (cur->name != NULL)
00980             xmlFree((char *)cur->name);
00981         if (cur->ExternalID != NULL)
00982             xmlFree((char *)cur->ExternalID);
00983         xmlFree(cur);
00984         return(NULL);
00985     }
00986     }
00987     if (doc != NULL) {
00988     doc->intSubset = cur;
00989     cur->parent = doc;
00990     cur->doc = doc;
00991     if (doc->children == NULL) {
00992         doc->children = (xmlNodePtr) cur;
00993         doc->last = (xmlNodePtr) cur;
00994     } else {
00995         if (doc->type == XML_HTML_DOCUMENT_NODE) {
00996         xmlNodePtr prev;
00997 
00998         prev = doc->children;
00999         prev->prev = (xmlNodePtr) cur;
01000         cur->next = prev;
01001         doc->children = (xmlNodePtr) cur;
01002         } else {
01003         xmlNodePtr next;
01004 
01005         next = doc->children;
01006         while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
01007             next = next->next;
01008         if (next == NULL) {
01009             cur->prev = doc->last;
01010             cur->prev->next = (xmlNodePtr) cur;
01011             cur->next = NULL;
01012             doc->last = (xmlNodePtr) cur;
01013         } else {
01014             cur->next = next;
01015             cur->prev = next->prev;
01016             if (cur->prev == NULL)
01017             doc->children = (xmlNodePtr) cur;
01018             else
01019             cur->prev->next = (xmlNodePtr) cur;
01020             next->prev = (xmlNodePtr) cur;
01021         }
01022         }
01023     }
01024     }
01025 
01026     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
01027     xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
01028     return(cur);
01029 }
01030 
01038 #define DICT_FREE(str)                      \
01039     if ((str) && ((!dict) ||                \
01040         (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))  \
01041         xmlFree((char *)(str));
01042 
01043 
01051 #define DICT_COPY(str, cpy) \
01052     if (str) { \
01053     if (dict) { \
01054         if (xmlDictOwns(dict, (const xmlChar *)(str))) \
01055         cpy = (xmlChar *) (str); \
01056         else \
01057         cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
01058     } else \
01059         cpy = xmlStrdup((const xmlChar *)(str)); }
01060 
01068 #define DICT_CONST_COPY(str, cpy) \
01069     if (str) { \
01070     if (dict) { \
01071         if (xmlDictOwns(dict, (const xmlChar *)(str))) \
01072         cpy = (const xmlChar *) (str); \
01073         else \
01074         cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
01075     } else \
01076         cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
01077 
01078 
01085 void
01086 xmlFreeDtd(xmlDtdPtr cur) {
01087     xmlDictPtr dict = NULL;
01088 
01089     if (cur == NULL) {
01090     return;
01091     }
01092     if (cur->doc != NULL) dict = cur->doc->dict;
01093 
01094     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
01095     xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
01096 
01097     if (cur->children != NULL) {
01098     xmlNodePtr next, c = cur->children;
01099 
01100     /*
01101      * Cleanup all nodes which are not part of the specific lists
01102      * of notations, elements, attributes and entities.
01103      */
01104         while (c != NULL) {
01105         next = c->next;
01106         if ((c->type != XML_NOTATION_NODE) &&
01107             (c->type != XML_ELEMENT_DECL) &&
01108         (c->type != XML_ATTRIBUTE_DECL) &&
01109         (c->type != XML_ENTITY_DECL)) {
01110         xmlUnlinkNode(c);
01111         xmlFreeNode(c);
01112         }
01113         c = next;
01114     }
01115     }
01116     DICT_FREE(cur->name)
01117     DICT_FREE(cur->SystemID)
01118     DICT_FREE(cur->ExternalID)
01119     /* TODO !!! */
01120     if (cur->notations != NULL)
01121         xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
01122 
01123     if (cur->elements != NULL)
01124         xmlFreeElementTable((xmlElementTablePtr) cur->elements);
01125     if (cur->attributes != NULL)
01126         xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
01127     if (cur->entities != NULL)
01128         xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
01129     if (cur->pentities != NULL)
01130         xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
01131 
01132     xmlFree(cur);
01133 }
01134 
01143 xmlDocPtr
01144 xmlNewDoc(const xmlChar *version) {
01145     xmlDocPtr cur;
01146 
01147     if (version == NULL)
01148     version = (const xmlChar *) "1.0";
01149 
01150     /*
01151      * Allocate a new document and fill the fields.
01152      */
01153     cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
01154     if (cur == NULL) {
01155     xmlTreeErrMemory("building doc");
01156     return(NULL);
01157     }
01158     memset(cur, 0, sizeof(xmlDoc));
01159     cur->type = XML_DOCUMENT_NODE;
01160 
01161     cur->version = xmlStrdup(version);
01162     if (cur->version == NULL) {
01163     xmlTreeErrMemory("building doc");
01164     xmlFree(cur);
01165     return(NULL);
01166     }
01167     cur->standalone = -1;
01168     cur->compression = -1; /* not initialized */
01169     cur->doc = cur;
01170     cur->parseFlags = 0;
01171     cur->properties = XML_DOC_USERBUILT;
01172     /*
01173      * The in memory encoding is always UTF8
01174      * This field will never change and would
01175      * be obsolete if not for binary compatibility.
01176      */
01177     cur->charset = XML_CHAR_ENCODING_UTF8;
01178 
01179     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
01180     xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
01181     return(cur);
01182 }
01183 
01190 void
01191 xmlFreeDoc(xmlDocPtr cur) {
01192     xmlDtdPtr extSubset, intSubset;
01193     xmlDictPtr dict = NULL;
01194 
01195     if (cur == NULL) {
01196 #ifdef DEBUG_TREE
01197         xmlGenericError(xmlGenericErrorContext,
01198         "xmlFreeDoc : document == NULL\n");
01199 #endif
01200     return;
01201     }
01202 #ifdef LIBXML_DEBUG_RUNTIME
01203 #ifdef LIBXML_DEBUG_ENABLED
01204     xmlDebugCheckDocument(stderr, cur);
01205 #endif
01206 #endif
01207 
01208     if (cur != NULL) dict = cur->dict;
01209 
01210     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
01211     xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
01212 
01213     /*
01214      * Do this before freeing the children list to avoid ID lookups
01215      */
01216     if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
01217     cur->ids = NULL;
01218     if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
01219     cur->refs = NULL;
01220     extSubset = cur->extSubset;
01221     intSubset = cur->intSubset;
01222     if (intSubset == extSubset)
01223     extSubset = NULL;
01224     if (extSubset != NULL) {
01225     xmlUnlinkNode((xmlNodePtr) cur->extSubset);
01226     cur->extSubset = NULL;
01227     xmlFreeDtd(extSubset);
01228     }
01229     if (intSubset != NULL) {
01230     xmlUnlinkNode((xmlNodePtr) cur->intSubset);
01231     cur->intSubset = NULL;
01232     xmlFreeDtd(intSubset);
01233     }
01234 
01235     if (cur->children != NULL) xmlFreeNodeList(cur->children);
01236     if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
01237 
01238     DICT_FREE(cur->version)
01239     DICT_FREE(cur->name)
01240     DICT_FREE(cur->encoding)
01241     DICT_FREE(cur->URL)
01242     xmlFree(cur);
01243     if (dict) xmlDictFree(dict);
01244 }
01245 
01256 xmlNodePtr
01257 xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
01258     xmlNodePtr ret = NULL, last = NULL;
01259     xmlNodePtr node;
01260     xmlChar *val;
01261     const xmlChar *cur = value, *end = cur + len;
01262     const xmlChar *q;
01263     xmlEntityPtr ent;
01264 
01265     if (value == NULL) return(NULL);
01266 
01267     q = cur;
01268     while ((cur < end) && (*cur != 0)) {
01269     if (cur[0] == '&') {
01270         int charval = 0;
01271         xmlChar tmp;
01272 
01273         /*
01274          * Save the current text.
01275          */
01276             if (cur != q) {
01277         if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
01278             xmlNodeAddContentLen(last, q, cur - q);
01279         } else {
01280             node = xmlNewDocTextLen(doc, q, cur - q);
01281             if (node == NULL) return(ret);
01282             if (last == NULL)
01283             last = ret = node;
01284             else {
01285             last->next = node;
01286             node->prev = last;
01287             last = node;
01288             }
01289         }
01290         }
01291         q = cur;
01292         if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
01293         cur += 3;
01294         if (cur < end)
01295             tmp = *cur;
01296         else
01297             tmp = 0;
01298         while (tmp != ';') { /* Non input consuming loop */
01299             if ((tmp >= '0') && (tmp <= '9'))
01300             charval = charval * 16 + (tmp - '0');
01301             else if ((tmp >= 'a') && (tmp <= 'f'))
01302             charval = charval * 16 + (tmp - 'a') + 10;
01303             else if ((tmp >= 'A') && (tmp <= 'F'))
01304             charval = charval * 16 + (tmp - 'A') + 10;
01305             else {
01306             xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
01307                        NULL);
01308             charval = 0;
01309             break;
01310             }
01311             cur++;
01312             if (cur < end)
01313             tmp = *cur;
01314             else
01315             tmp = 0;
01316         }
01317         if (tmp == ';')
01318             cur++;
01319         q = cur;
01320         } else if ((cur + 1 < end) && (cur[1] == '#')) {
01321         cur += 2;
01322         if (cur < end)
01323             tmp = *cur;
01324         else
01325             tmp = 0;
01326         while (tmp != ';') { /* Non input consuming loops */
01327             if ((tmp >= '0') && (tmp <= '9'))
01328             charval = charval * 10 + (tmp - '0');
01329             else {
01330             xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
01331                        NULL);
01332             charval = 0;
01333             break;
01334             }
01335             cur++;
01336             if (cur < end)
01337             tmp = *cur;
01338             else
01339             tmp = 0;
01340         }
01341         if (tmp == ';')
01342             cur++;
01343         q = cur;
01344         } else {
01345         /*
01346          * Read the entity string
01347          */
01348         cur++;
01349         q = cur;
01350         while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
01351         if ((cur >= end) || (*cur == 0)) {
01352             xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
01353                        (const char *) q);
01354             return(ret);
01355         }
01356         if (cur != q) {
01357             /*
01358              * Predefined entities don't generate nodes
01359              */
01360             val = xmlStrndup(q, cur - q);
01361             ent = xmlGetDocEntity(doc, val);
01362             if ((ent != NULL) &&
01363             (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
01364             if (last == NULL) {
01365                 node = xmlNewDocText(doc, ent->content);
01366                 last = ret = node;
01367             } else if (last->type != XML_TEXT_NODE) {
01368                 node = xmlNewDocText(doc, ent->content);
01369                 last = xmlAddNextSibling(last, node);
01370             } else
01371                 xmlNodeAddContent(last, ent->content);
01372 
01373             } else {
01374             /*
01375              * Create a new REFERENCE_REF node
01376              */
01377             node = xmlNewReference(doc, val);
01378             if (node == NULL) {
01379                 if (val != NULL) xmlFree(val);
01380                 return(ret);
01381             }
01382             else if ((ent != NULL) && (ent->children == NULL)) {
01383                 xmlNodePtr temp;
01384 
01385                 ent->children = xmlStringGetNodeList(doc,
01386                     (const xmlChar*)node->content);
01387                 ent->owner = 1;
01388                 temp = ent->children;
01389                 while (temp) {
01390                 temp->parent = (xmlNodePtr)ent;
01391                 ent->last = temp;
01392                 temp = temp->next;
01393                 }
01394             }
01395             if (last == NULL) {
01396                 last = ret = node;
01397             } else {
01398                 last = xmlAddNextSibling(last, node);
01399             }
01400             }
01401             xmlFree(val);
01402         }
01403         cur++;
01404         q = cur;
01405         }
01406         if (charval != 0) {
01407         xmlChar buf[10];
01408         int l;
01409 
01410         l = xmlCopyCharMultiByte(buf, charval);
01411         buf[l] = 0;
01412         node = xmlNewDocText(doc, buf);
01413         if (node != NULL) {
01414             if (last == NULL) {
01415             last = ret = node;
01416             } else {
01417             last = xmlAddNextSibling(last, node);
01418             }
01419         }
01420         charval = 0;
01421         }
01422     } else
01423         cur++;
01424     }
01425     if ((cur != q) || (ret == NULL)) {
01426         /*
01427      * Handle the last piece of text.
01428      */
01429     if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
01430         xmlNodeAddContentLen(last, q, cur - q);
01431     } else {
01432         node = xmlNewDocTextLen(doc, q, cur - q);
01433         if (node == NULL) return(ret);
01434         if (last == NULL) {
01435         ret = node;
01436         } else {
01437         xmlAddNextSibling(last, node);
01438         }
01439     }
01440     }
01441     return(ret);
01442 }
01443 
01453 xmlNodePtr
01454 xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
01455     xmlNodePtr ret = NULL, last = NULL;
01456     xmlNodePtr node;
01457     xmlChar *val;
01458     const xmlChar *cur = value;
01459     const xmlChar *q;
01460     xmlEntityPtr ent;
01461 
01462     if (value == NULL) return(NULL);
01463 
01464     q = cur;
01465     while (*cur != 0) {
01466     if (cur[0] == '&') {
01467         int charval = 0;
01468         xmlChar tmp;
01469 
01470         /*
01471          * Save the current text.
01472          */
01473             if (cur != q) {
01474         if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
01475             xmlNodeAddContentLen(last, q, cur - q);
01476         } else {
01477             node = xmlNewDocTextLen(doc, q, cur - q);
01478             if (node == NULL) return(ret);
01479             if (last == NULL)
01480             last = ret = node;
01481             else {
01482             last->next = node;
01483             node->prev = last;
01484             last = node;
01485             }
01486         }
01487         }
01488         q = cur;
01489         if ((cur[1] == '#') && (cur[2] == 'x')) {
01490         cur += 3;
01491         tmp = *cur;
01492         while (tmp != ';') { /* Non input consuming loop */
01493             if ((tmp >= '0') && (tmp <= '9'))
01494             charval = charval * 16 + (tmp - '0');
01495             else if ((tmp >= 'a') && (tmp <= 'f'))
01496             charval = charval * 16 + (tmp - 'a') + 10;
01497             else if ((tmp >= 'A') && (tmp <= 'F'))
01498             charval = charval * 16 + (tmp - 'A') + 10;
01499             else {
01500             xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
01501                        NULL);
01502             charval = 0;
01503             break;
01504             }
01505             cur++;
01506             tmp = *cur;
01507         }
01508         if (tmp == ';')
01509             cur++;
01510         q = cur;
01511         } else if  (cur[1] == '#') {
01512         cur += 2;
01513         tmp = *cur;
01514         while (tmp != ';') { /* Non input consuming loops */
01515             if ((tmp >= '0') && (tmp <= '9'))
01516             charval = charval * 10 + (tmp - '0');
01517             else {
01518             xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
01519                        NULL);
01520             charval = 0;
01521             break;
01522             }
01523             cur++;
01524             tmp = *cur;
01525         }
01526         if (tmp == ';')
01527             cur++;
01528         q = cur;
01529         } else {
01530         /*
01531          * Read the entity string
01532          */
01533         cur++;
01534         q = cur;
01535         while ((*cur != 0) && (*cur != ';')) cur++;
01536         if (*cur == 0) {
01537             xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
01538                        (xmlNodePtr) doc, (const char *) q);
01539             return(ret);
01540         }
01541         if (cur != q) {
01542             /*
01543              * Predefined entities don't generate nodes
01544              */
01545             val = xmlStrndup(q, cur - q);
01546             ent = xmlGetDocEntity(doc, val);
01547             if ((ent != NULL) &&
01548             (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
01549             if (last == NULL) {
01550                 node = xmlNewDocText(doc, ent->content);
01551                 last = ret = node;
01552             } else if (last->type != XML_TEXT_NODE) {
01553                 node = xmlNewDocText(doc, ent->content);
01554                 last = xmlAddNextSibling(last, node);
01555             } else
01556                 xmlNodeAddContent(last, ent->content);
01557 
01558             } else {
01559             /*
01560              * Create a new REFERENCE_REF node
01561              */
01562             node = xmlNewReference(doc, val);
01563             if (node == NULL) {
01564                 if (val != NULL) xmlFree(val);
01565                 return(ret);
01566             }
01567             else if ((ent != NULL) && (ent->children == NULL)) {
01568                 xmlNodePtr temp;
01569 
01570                 ent->children = xmlStringGetNodeList(doc,
01571                     (const xmlChar*)node->content);
01572                 ent->owner = 1;
01573                 temp = ent->children;
01574                 while (temp) {
01575                 temp->parent = (xmlNodePtr)ent;
01576                 temp = temp->next;
01577                 }
01578             }
01579             if (last == NULL) {
01580                 last = ret = node;
01581             } else {
01582                 last = xmlAddNextSibling(last, node);
01583             }
01584             }
01585             xmlFree(val);
01586         }
01587         cur++;
01588         q = cur;
01589         }
01590         if (charval != 0) {
01591         xmlChar buf[10];
01592         int len;
01593 
01594         len = xmlCopyCharMultiByte(buf, charval);
01595         buf[len] = 0;
01596         node = xmlNewDocText(doc, buf);
01597         if (node != NULL) {
01598             if (last == NULL) {
01599             last = ret = node;
01600             } else {
01601             last = xmlAddNextSibling(last, node);
01602             }
01603         }
01604         }
01605     } else
01606         cur++;
01607     }
01608     if ((cur != q) || (ret == NULL)) {
01609         /*
01610      * Handle the last piece of text.
01611      */
01612     if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
01613         xmlNodeAddContentLen(last, q, cur - q);
01614     } else {
01615         node = xmlNewDocTextLen(doc, q, cur - q);
01616         if (node == NULL) return(ret);
01617         if (last == NULL) {
01618         last = ret = node;
01619         } else {
01620         last = xmlAddNextSibling(last, node);
01621         }
01622     }
01623     }
01624     return(ret);
01625 }
01626 
01638 xmlChar *
01639 xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
01640 {
01641     xmlNodePtr node = list;
01642     xmlChar *ret = NULL;
01643     xmlEntityPtr ent;
01644 
01645     if (list == NULL)
01646         return (NULL);
01647 
01648     while (node != NULL) {
01649         if ((node->type == XML_TEXT_NODE) ||
01650             (node->type == XML_CDATA_SECTION_NODE)) {
01651             if (inLine) {
01652                 ret = xmlStrcat(ret, node->content);
01653             } else {
01654                 xmlChar *buffer;
01655 
01656                 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
01657                 if (buffer != NULL) {
01658                     ret = xmlStrcat(ret, buffer);
01659                     xmlFree(buffer);
01660                 }
01661             }
01662         } else if (node->type == XML_ENTITY_REF_NODE) {
01663             if (inLine) {
01664                 ent = xmlGetDocEntity(doc, node->name);
01665                 if (ent != NULL) {
01666                     xmlChar *buffer;
01667 
01668                     /* an entity content can be any "well balanced chunk",
01669                      * i.e. the result of the content [43] production:
01670                      * http://www.w3.org/TR/REC-xml#NT-content.
01671                      * So it can contain text, CDATA section or nested
01672                      * entity reference nodes (among others).
01673                      * -> we recursive  call xmlNodeListGetString()
01674                      * which handles these types */
01675                     buffer = xmlNodeListGetString(doc, ent->children, 1);
01676                     if (buffer != NULL) {
01677                         ret = xmlStrcat(ret, buffer);
01678                         xmlFree(buffer);
01679                     }
01680                 } else {
01681                     ret = xmlStrcat(ret, node->content);
01682                 }
01683             } else {
01684                 xmlChar buf[2];
01685 
01686                 buf[0] = '&';
01687                 buf[1] = 0;
01688                 ret = xmlStrncat(ret, buf, 1);
01689                 ret = xmlStrcat(ret, node->name);
01690                 buf[0] = ';';
01691                 buf[1] = 0;
01692                 ret = xmlStrncat(ret, buf, 1);
01693             }
01694         }
01695 #if 0
01696         else {
01697             xmlGenericError(xmlGenericErrorContext,
01698                             "xmlGetNodeListString : invalid node type %d\n",
01699                             node->type);
01700         }
01701 #endif
01702         node = node->next;
01703     }
01704     return (ret);
01705 }
01706 
01707 #ifdef LIBXML_TREE_ENABLED
01708 
01720 xmlChar *
01721 xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
01722 {
01723     xmlNodePtr node = list;
01724     xmlChar *ret = NULL;
01725     xmlEntityPtr ent;
01726 
01727     if (list == NULL)
01728         return (NULL);
01729 
01730     while (node != NULL) {
01731         if ((node->type == XML_TEXT_NODE) ||
01732             (node->type == XML_CDATA_SECTION_NODE)) {
01733             if (inLine) {
01734                 ret = xmlStrcat(ret, node->content);
01735             } else {
01736                 xmlChar *buffer;
01737 
01738                 buffer = xmlEncodeSpecialChars(doc, node->content);
01739                 if (buffer != NULL) {
01740                     ret = xmlStrcat(ret, buffer);
01741                     xmlFree(buffer);
01742                 }
01743             }
01744         } else if (node->type == XML_ENTITY_REF_NODE) {
01745             if (inLine) {
01746                 ent = xmlGetDocEntity(doc, node->name);
01747                 if (ent != NULL) {
01748                     xmlChar *buffer;
01749 
01750                     /* an entity content can be any "well balanced chunk",
01751                      * i.e. the result of the content [43] production:
01752                      * http://www.w3.org/TR/REC-xml#NT-content.
01753                      * So it can contain text, CDATA section or nested
01754                      * entity reference nodes (among others).
01755                      * -> we recursive  call xmlNodeListGetRawString()
01756                      * which handles these types */
01757                     buffer =
01758                         xmlNodeListGetRawString(doc, ent->children, 1);
01759                     if (buffer != NULL) {
01760                         ret = xmlStrcat(ret, buffer);
01761                         xmlFree(buffer);
01762                     }
01763                 } else {
01764                     ret = xmlStrcat(ret, node->content);
01765                 }
01766             } else {
01767                 xmlChar buf[2];
01768 
01769                 buf[0] = '&';
01770                 buf[1] = 0;
01771                 ret = xmlStrncat(ret, buf, 1);
01772                 ret = xmlStrcat(ret, node->name);
01773                 buf[0] = ';';
01774                 buf[1] = 0;
01775                 ret = xmlStrncat(ret, buf, 1);
01776             }
01777         }
01778 #if 0
01779         else {
01780             xmlGenericError(xmlGenericErrorContext,
01781                             "xmlGetNodeListString : invalid node type %d\n",
01782                             node->type);
01783         }
01784 #endif
01785         node = node->next;
01786     }
01787     return (ret);
01788 }
01789 #endif /* LIBXML_TREE_ENABLED */
01790 
01791 static xmlAttrPtr
01792 xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
01793                    const xmlChar * name, const xmlChar * value,
01794                    int eatname)
01795 {
01796     xmlAttrPtr cur;
01797     xmlDocPtr doc = NULL;
01798 
01799     if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
01800         if ((eatname == 1) &&
01801         ((node->doc == NULL) ||
01802          (!(xmlDictOwns(node->doc->dict, name)))))
01803             xmlFree((xmlChar *) name);
01804         return (NULL);
01805     }
01806 
01807     /*
01808      * Allocate a new property and fill the fields.
01809      */
01810     cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
01811     if (cur == NULL) {
01812         if ((eatname == 1) &&
01813         ((node == NULL) || (node->doc == NULL) ||
01814          (!(xmlDictOwns(node->doc->dict, name)))))
01815             xmlFree((xmlChar *) name);
01816         xmlTreeErrMemory("building attribute");
01817         return (NULL);
01818     }
01819     memset(cur, 0, sizeof(xmlAttr));
01820     cur->type = XML_ATTRIBUTE_NODE;
01821 
01822     cur->parent = node;
01823     if (node != NULL) {
01824         doc = node->doc;
01825         cur->doc = doc;
01826     }
01827     cur->ns = ns;
01828 
01829     if (eatname == 0) {
01830         if ((doc != NULL) && (doc->dict != NULL))
01831             cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
01832         else
01833             cur->name = xmlStrdup(name);
01834     } else
01835         cur->name = name;
01836 
01837     if (value != NULL) {
01838         xmlNodePtr tmp;
01839 
01840         if(!xmlCheckUTF8(value)) {
01841             xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) doc,
01842                        NULL);
01843             if (doc != NULL)
01844                 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
01845         }
01846         cur->children = xmlNewDocText(doc, value);
01847         cur->last = NULL;
01848         tmp = cur->children;
01849         while (tmp != NULL) {
01850             tmp->parent = (xmlNodePtr) cur;
01851             if (tmp->next == NULL)
01852                 cur->last = tmp;
01853             tmp = tmp->next;
01854         }
01855     }
01856 
01857     /*
01858      * Add it at the end to preserve parsing order ...
01859      */
01860     if (node != NULL) {
01861         if (node->properties == NULL) {
01862             node->properties = cur;
01863         } else {
01864             xmlAttrPtr prev = node->properties;
01865 
01866             while (prev->next != NULL)
01867                 prev = prev->next;
01868             prev->next = cur;
01869             cur->prev = prev;
01870         }
01871     }
01872 
01873     if ((value != NULL) && (node != NULL) &&
01874         (xmlIsID(node->doc, node, cur) == 1))
01875         xmlAddID(NULL, node->doc, value, cur);
01876 
01877     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
01878         xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
01879     return (cur);
01880 }
01881 
01882 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
01883     defined(LIBXML_SCHEMAS_ENABLED)
01884 
01893 xmlAttrPtr
01894 xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
01895 
01896     if (name == NULL) {
01897 #ifdef DEBUG_TREE
01898         xmlGenericError(xmlGenericErrorContext,
01899         "xmlNewProp : name == NULL\n");
01900 #endif
01901     return(NULL);
01902     }
01903 
01904     return xmlNewPropInternal(node, NULL, name, value, 0);
01905 }
01906 #endif /* LIBXML_TREE_ENABLED */
01907 
01918 xmlAttrPtr
01919 xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
01920            const xmlChar *value) {
01921 
01922     if (name == NULL) {
01923 #ifdef DEBUG_TREE
01924         xmlGenericError(xmlGenericErrorContext,
01925         "xmlNewNsProp : name == NULL\n");
01926 #endif
01927     return(NULL);
01928     }
01929 
01930     return xmlNewPropInternal(node, ns, name, value, 0);
01931 }
01932 
01943 xmlAttrPtr
01944 xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
01945            const xmlChar *value) {
01946 
01947     if (name == NULL) {
01948 #ifdef DEBUG_TREE
01949         xmlGenericError(xmlGenericErrorContext,
01950         "xmlNewNsPropEatName : name == NULL\n");
01951 #endif
01952     return(NULL);
01953     }
01954 
01955     return xmlNewPropInternal(node, ns, name, value, 1);
01956 }
01957 
01967 xmlAttrPtr
01968 xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
01969     xmlAttrPtr cur;
01970 
01971     if (name == NULL) {
01972 #ifdef DEBUG_TREE
01973         xmlGenericError(xmlGenericErrorContext,
01974         "xmlNewDocProp : name == NULL\n");
01975 #endif
01976     return(NULL);
01977     }
01978 
01979     /*
01980      * Allocate a new property and fill the fields.
01981      */
01982     cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
01983     if (cur == NULL) {
01984     xmlTreeErrMemory("building attribute");
01985     return(NULL);
01986     }
01987     memset(cur, 0, sizeof(xmlAttr));
01988     cur->type = XML_ATTRIBUTE_NODE;
01989 
01990     if ((doc != NULL) && (doc->dict != NULL))
01991     cur->name = xmlDictLookup(doc->dict, name, -1);
01992     else
01993     cur->name = xmlStrdup(name);
01994     cur->doc = doc;
01995     if (value != NULL) {
01996     xmlNodePtr tmp;
01997 
01998     cur->children = xmlStringGetNodeList(doc, value);
01999     cur->last = NULL;
02000 
02001     tmp = cur->children;
02002     while (tmp != NULL) {
02003         tmp->parent = (xmlNodePtr) cur;
02004         if (tmp->next == NULL)
02005         cur->last = tmp;
02006         tmp = tmp->next;
02007     }
02008     }
02009 
02010     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02011     xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
02012     return(cur);
02013 }
02014 
02021 void
02022 xmlFreePropList(xmlAttrPtr cur) {
02023     xmlAttrPtr next;
02024     if (cur == NULL) return;
02025     while (cur != NULL) {
02026         next = cur->next;
02027         xmlFreeProp(cur);
02028     cur = next;
02029     }
02030 }
02031 
02038 void
02039 xmlFreeProp(xmlAttrPtr cur) {
02040     xmlDictPtr dict = NULL;
02041     if (cur == NULL) return;
02042 
02043     if (cur->doc != NULL) dict = cur->doc->dict;
02044 
02045     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
02046     xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
02047 
02048     /* Check for ID removal -> leading to invalid references ! */
02049     if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
02050         xmlRemoveID(cur->doc, cur);
02051     }
02052     if (cur->children != NULL) xmlFreeNodeList(cur->children);
02053     DICT_FREE(cur->name)
02054     xmlFree(cur);
02055 }
02056 
02066 int
02067 xmlRemoveProp(xmlAttrPtr cur) {
02068     xmlAttrPtr tmp;
02069     if (cur == NULL) {
02070 #ifdef DEBUG_TREE
02071         xmlGenericError(xmlGenericErrorContext,
02072         "xmlRemoveProp : cur == NULL\n");
02073 #endif
02074     return(-1);
02075     }
02076     if (cur->parent == NULL) {
02077 #ifdef DEBUG_TREE
02078         xmlGenericError(xmlGenericErrorContext,
02079         "xmlRemoveProp : cur->parent == NULL\n");
02080 #endif
02081     return(-1);
02082     }
02083     tmp = cur->parent->properties;
02084     if (tmp == cur) {
02085         cur->parent->properties = cur->next;
02086         if (cur->next != NULL)
02087             cur->next->prev = NULL;
02088     xmlFreeProp(cur);
02089     return(0);
02090     }
02091     while (tmp != NULL) {
02092     if (tmp->next == cur) {
02093         tmp->next = cur->next;
02094         if (tmp->next != NULL)
02095         tmp->next->prev = tmp;
02096         xmlFreeProp(cur);
02097         return(0);
02098     }
02099         tmp = tmp->next;
02100     }
02101 #ifdef DEBUG_TREE
02102     xmlGenericError(xmlGenericErrorContext,
02103         "xmlRemoveProp : attribute not owned by its node\n");
02104 #endif
02105     return(-1);
02106 }
02107 
02117 xmlNodePtr
02118 xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
02119     xmlNodePtr cur;
02120 
02121     if (name == NULL) {
02122 #ifdef DEBUG_TREE
02123         xmlGenericError(xmlGenericErrorContext,
02124         "xmlNewPI : name == NULL\n");
02125 #endif
02126     return(NULL);
02127     }
02128 
02129     /*
02130      * Allocate a new node and fill the fields.
02131      */
02132     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
02133     if (cur == NULL) {
02134     xmlTreeErrMemory("building PI");
02135     return(NULL);
02136     }
02137     memset(cur, 0, sizeof(xmlNode));
02138     cur->type = XML_PI_NODE;
02139 
02140     if ((doc != NULL) && (doc->dict != NULL))
02141         cur->name = xmlDictLookup(doc->dict, name, -1);
02142     else
02143     cur->name = xmlStrdup(name);
02144     if (content != NULL) {
02145     cur->content = xmlStrdup(content);
02146     }
02147     cur->doc = doc;
02148 
02149     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02150     xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
02151     return(cur);
02152 }
02153 
02164 xmlNodePtr
02165 xmlNewPI(const xmlChar *name, const xmlChar *content) {
02166     return(xmlNewDocPI(NULL, name, content));
02167 }
02168 
02179 xmlNodePtr
02180 xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
02181     xmlNodePtr cur;
02182 
02183     if (name == NULL) {
02184 #ifdef DEBUG_TREE
02185         xmlGenericError(xmlGenericErrorContext,
02186         "xmlNewNode : name == NULL\n");
02187 #endif
02188     return(NULL);
02189     }
02190 
02191     /*
02192      * Allocate a new node and fill the fields.
02193      */
02194     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
02195     if (cur == NULL) {
02196     xmlTreeErrMemory("building node");
02197     return(NULL);
02198     }
02199     memset(cur, 0, sizeof(xmlNode));
02200     cur->type = XML_ELEMENT_NODE;
02201 
02202     cur->name = xmlStrdup(name);
02203     cur->ns = ns;
02204 
02205     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02206     xmlRegisterNodeDefaultValue(cur);
02207     return(cur);
02208 }
02209 
02221 xmlNodePtr
02222 xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
02223     xmlNodePtr cur;
02224 
02225     if (name == NULL) {
02226 #ifdef DEBUG_TREE
02227         xmlGenericError(xmlGenericErrorContext,
02228         "xmlNewNode : name == NULL\n");
02229 #endif
02230     return(NULL);
02231     }
02232 
02233     /*
02234      * Allocate a new node and fill the fields.
02235      */
02236     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
02237     if (cur == NULL) {
02238     xmlTreeErrMemory("building node");
02239     /* we can't check here that name comes from the doc dictionnary */
02240     return(NULL);
02241     }
02242     memset(cur, 0, sizeof(xmlNode));
02243     cur->type = XML_ELEMENT_NODE;
02244 
02245     cur->name = name;
02246     cur->ns = ns;
02247 
02248     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02249     xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
02250     return(cur);
02251 }
02252 
02269 xmlNodePtr
02270 xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
02271               const xmlChar *name, const xmlChar *content) {
02272     xmlNodePtr cur;
02273 
02274     if ((doc != NULL) && (doc->dict != NULL))
02275         cur = xmlNewNodeEatName(ns, (xmlChar *)
02276                             xmlDictLookup(doc->dict, name, -1));
02277     else
02278     cur = xmlNewNode(ns, name);
02279     if (cur != NULL) {
02280         cur->doc = doc;
02281     if (content != NULL) {
02282         cur->children = xmlStringGetNodeList(doc, content);
02283         UPDATE_LAST_CHILD_AND_PARENT(cur)
02284     }
02285     }
02286 
02287     return(cur);
02288 }
02289 
02306 xmlNodePtr
02307 xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
02308               xmlChar *name, const xmlChar *content) {
02309     xmlNodePtr cur;
02310 
02311     cur = xmlNewNodeEatName(ns, name);
02312     if (cur != NULL) {
02313         cur->doc = doc;
02314     if (content != NULL) {
02315         cur->children = xmlStringGetNodeList(doc, content);
02316         UPDATE_LAST_CHILD_AND_PARENT(cur)
02317     }
02318     } else {
02319         /* if name don't come from the doc dictionnary free it here */
02320         if ((name != NULL) && (doc != NULL) &&
02321         (!(xmlDictOwns(doc->dict, name))))
02322         xmlFree(name);
02323     }
02324     return(cur);
02325 }
02326 
02327 #ifdef LIBXML_TREE_ENABLED
02328 
02340 xmlNodePtr
02341 xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
02342                  const xmlChar *name, const xmlChar *content) {
02343     xmlNodePtr cur;
02344 
02345     cur = xmlNewDocNode(doc, ns, name, NULL);
02346     if (cur != NULL) {
02347         cur->doc = doc;
02348     if (content != NULL) {
02349         cur->children = xmlNewDocText(doc, content);
02350         UPDATE_LAST_CHILD_AND_PARENT(cur)
02351     }
02352     }
02353     return(cur);
02354 }
02355 
02363 xmlNodePtr
02364 xmlNewDocFragment(xmlDocPtr doc) {
02365     xmlNodePtr cur;
02366 
02367     /*
02368      * Allocate a new DocumentFragment node and fill the fields.
02369      */
02370     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
02371     if (cur == NULL) {
02372     xmlTreeErrMemory("building fragment");
02373     return(NULL);
02374     }
02375     memset(cur, 0, sizeof(xmlNode));
02376     cur->type = XML_DOCUMENT_FRAG_NODE;
02377 
02378     cur->doc = doc;
02379 
02380     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02381     xmlRegisterNodeDefaultValue(cur);
02382     return(cur);
02383 }
02384 #endif /* LIBXML_TREE_ENABLED */
02385 
02393 xmlNodePtr
02394 xmlNewText(const xmlChar *content) {
02395     xmlNodePtr cur;
02396 
02397     /*
02398      * Allocate a new node and fill the fields.
02399      */
02400     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
02401     if (cur == NULL) {
02402     xmlTreeErrMemory("building text");
02403     return(NULL);
02404     }
02405     memset(cur, 0, sizeof(xmlNode));
02406     cur->type = XML_TEXT_NODE;
02407 
02408     cur->name = xmlStringText;
02409     if (content != NULL) {
02410     cur->content = xmlStrdup(content);
02411     }
02412 
02413     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02414     xmlRegisterNodeDefaultValue(cur);
02415     return(cur);
02416 }
02417 
02418 #ifdef LIBXML_TREE_ENABLED
02419 
02438 xmlNodePtr
02439 xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
02440             const xmlChar *name, const xmlChar *content) {
02441     xmlNodePtr cur, prev;
02442 
02443     if (parent == NULL) {
02444 #ifdef DEBUG_TREE
02445         xmlGenericError(xmlGenericErrorContext,
02446         "xmlNewTextChild : parent == NULL\n");
02447 #endif
02448     return(NULL);
02449     }
02450 
02451     if (name == NULL) {
02452 #ifdef DEBUG_TREE
02453         xmlGenericError(xmlGenericErrorContext,
02454         "xmlNewTextChild : name == NULL\n");
02455 #endif
02456     return(NULL);
02457     }
02458 
02459     /*
02460      * Allocate a new node
02461      */
02462     if (parent->type == XML_ELEMENT_NODE) {
02463     if (ns == NULL)
02464         cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
02465     else
02466         cur = xmlNewDocRawNode(parent->doc, ns, name, content);
02467     } else if ((parent->type == XML_DOCUMENT_NODE) ||
02468            (parent->type == XML_HTML_DOCUMENT_NODE)) {
02469     if (ns == NULL)
02470         cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
02471     else
02472         cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
02473     } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
02474         cur = xmlNewDocRawNode( parent->doc, ns, name, content);
02475     } else {
02476     return(NULL);
02477     }
02478     if (cur == NULL) return(NULL);
02479 
02480     /*
02481      * add the new element at the end of the children list.
02482      */
02483     cur->type = XML_ELEMENT_NODE;
02484     cur->parent = parent;
02485     cur->doc = parent->doc;
02486     if (parent->children == NULL) {
02487         parent->children = cur;
02488     parent->last = cur;
02489     } else {
02490         prev = parent->last;
02491     prev->next = cur;
02492     cur->prev = prev;
02493     parent->last = cur;
02494     }
02495 
02496     return(cur);
02497 }
02498 #endif /* LIBXML_TREE_ENABLED */
02499 
02508 xmlNodePtr
02509 xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
02510     xmlNodePtr cur;
02511 
02512     if (name == NULL)
02513         return(NULL);
02514 
02515     /*
02516      * Allocate a new node and fill the fields.
02517      */
02518     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
02519     if (cur == NULL) {
02520     xmlTreeErrMemory("building character reference");
02521     return(NULL);
02522     }
02523     memset(cur, 0, sizeof(xmlNode));
02524     cur->type = XML_ENTITY_REF_NODE;
02525 
02526     cur->doc = doc;
02527     if (name[0] == '&') {
02528         int len;
02529         name++;
02530     len = xmlStrlen(name);
02531     if (name[len - 1] == ';')
02532         cur->name = xmlStrndup(name, len - 1);
02533     else
02534         cur->name = xmlStrndup(name, len);
02535     } else
02536     cur->name = xmlStrdup(name);
02537 
02538     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02539     xmlRegisterNodeDefaultValue(cur);
02540     return(cur);
02541 }
02542 
02551 xmlNodePtr
02552 xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
02553     xmlNodePtr cur;
02554     xmlEntityPtr ent;
02555 
02556     if (name == NULL)
02557         return(NULL);
02558 
02559     /*
02560      * Allocate a new node and fill the fields.
02561      */
02562     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
02563     if (cur == NULL) {
02564     xmlTreeErrMemory("building reference");
02565     return(NULL);
02566     }
02567     memset(cur, 0, sizeof(xmlNode));
02568     cur->type = XML_ENTITY_REF_NODE;
02569 
02570     cur->doc = doc;
02571     if (name[0] == '&') {
02572         int len;
02573         name++;
02574     len = xmlStrlen(name);
02575     if (name[len - 1] == ';')
02576         cur->name = xmlStrndup(name, len - 1);
02577     else
02578         cur->name = xmlStrndup(name, len);
02579     } else
02580     cur->name = xmlStrdup(name);
02581 
02582     ent = xmlGetDocEntity(doc, cur->name);
02583     if (ent != NULL) {
02584     cur->content = ent->content;
02585     /*
02586      * The parent pointer in entity is a DTD pointer and thus is NOT
02587      * updated.  Not sure if this is 100% correct.
02588      *  -George
02589      */
02590     cur->children = (xmlNodePtr) ent;
02591     cur->last = (xmlNodePtr) ent;
02592     }
02593 
02594     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02595     xmlRegisterNodeDefaultValue(cur);
02596     return(cur);
02597 }
02598 
02607 xmlNodePtr
02608 xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
02609     xmlNodePtr cur;
02610 
02611     cur = xmlNewText(content);
02612     if (cur != NULL) cur->doc = doc;
02613     return(cur);
02614 }
02615 
02624 xmlNodePtr
02625 xmlNewTextLen(const xmlChar *content, int len) {
02626     xmlNodePtr cur;
02627 
02628     /*
02629      * Allocate a new node and fill the fields.
02630      */
02631     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
02632     if (cur == NULL) {
02633     xmlTreeErrMemory("building text");
02634     return(NULL);
02635     }
02636     memset(cur, 0, sizeof(xmlNode));
02637     cur->type = XML_TEXT_NODE;
02638 
02639     cur->name = xmlStringText;
02640     if (content != NULL) {
02641     cur->content = xmlStrndup(content, len);
02642     }
02643 
02644     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02645     xmlRegisterNodeDefaultValue(cur);
02646     return(cur);
02647 }
02648 
02659 xmlNodePtr
02660 xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
02661     xmlNodePtr cur;
02662 
02663     cur = xmlNewTextLen(content, len);
02664     if (cur != NULL) cur->doc = doc;
02665     return(cur);
02666 }
02667 
02675 xmlNodePtr
02676 xmlNewComment(const xmlChar *content) {
02677     xmlNodePtr cur;
02678 
02679     /*
02680      * Allocate a new node and fill the fields.
02681      */
02682     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
02683     if (cur == NULL) {
02684     xmlTreeErrMemory("building comment");
02685     return(NULL);
02686     }
02687     memset(cur, 0, sizeof(xmlNode));
02688     cur->type = XML_COMMENT_NODE;
02689 
02690     cur->name = xmlStringComment;
02691     if (content != NULL) {
02692     cur->content = xmlStrdup(content);
02693     }
02694 
02695     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02696     xmlRegisterNodeDefaultValue(cur);
02697     return(cur);
02698 }
02699 
02709 xmlNodePtr
02710 xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
02711     xmlNodePtr cur;
02712 
02713     /*
02714      * Allocate a new node and fill the fields.
02715      */
02716     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
02717     if (cur == NULL) {
02718     xmlTreeErrMemory("building CDATA");
02719     return(NULL);
02720     }
02721     memset(cur, 0, sizeof(xmlNode));
02722     cur->type = XML_CDATA_SECTION_NODE;
02723     cur->doc = doc;
02724 
02725     if (content != NULL) {
02726     cur->content = xmlStrndup(content, len);
02727     }
02728 
02729     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
02730     xmlRegisterNodeDefaultValue(cur);
02731     return(cur);
02732 }
02733 
02742 xmlNodePtr
02743 xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
02744     xmlNodePtr cur;
02745 
02746     cur = xmlNewComment(content);
02747     if (cur != NULL) cur->doc = doc;
02748     return(cur);
02749 }
02750 
02758 void
02759 xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
02760     xmlAttrPtr prop;
02761 
02762     if (tree == NULL)
02763     return;
02764     if (tree->doc != doc) {
02765     if(tree->type == XML_ELEMENT_NODE) {
02766         prop = tree->properties;
02767         while (prop != NULL) {
02768         prop->doc = doc;
02769         xmlSetListDoc(prop->children, doc);
02770         prop = prop->next;
02771         }
02772     }
02773     if (tree->children != NULL)
02774         xmlSetListDoc(tree->children, doc);
02775     tree->doc = doc;
02776     }
02777 }
02778 
02786 void
02787 xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
02788     xmlNodePtr cur;
02789 
02790     if (list == NULL)
02791     return;
02792     cur = list;
02793     while (cur != NULL) {
02794     if (cur->doc != doc)
02795         xmlSetTreeDoc(cur, doc);
02796     cur = cur->next;
02797     }
02798 }
02799 
02800 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
02801 
02818 xmlNodePtr
02819 xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
02820             const xmlChar *name, const xmlChar *content) {
02821     xmlNodePtr cur, prev;
02822 
02823     if (parent == NULL) {
02824 #ifdef DEBUG_TREE
02825         xmlGenericError(xmlGenericErrorContext,
02826         "xmlNewChild : parent == NULL\n");
02827 #endif
02828     return(NULL);
02829     }
02830 
02831     if (name == NULL) {
02832 #ifdef DEBUG_TREE
02833         xmlGenericError(xmlGenericErrorContext,
02834         "xmlNewChild : name == NULL\n");
02835 #endif
02836     return(NULL);
02837     }
02838 
02839     /*
02840      * Allocate a new node
02841      */
02842     if (parent->type == XML_ELEMENT_NODE) {
02843     if (ns == NULL)
02844         cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
02845     else
02846         cur = xmlNewDocNode(parent->doc, ns, name, content);
02847     } else if ((parent->type == XML_DOCUMENT_NODE) ||
02848            (parent->type == XML_HTML_DOCUMENT_NODE)) {
02849     if (ns == NULL)
02850         cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
02851     else
02852         cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
02853     } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
02854         cur = xmlNewDocNode( parent->doc, ns, name, content);
02855     } else {
02856     return(NULL);
02857     }
02858     if (cur == NULL) return(NULL);
02859 
02860     /*
02861      * add the new element at the end of the children list.
02862      */
02863     cur->type = XML_ELEMENT_NODE;
02864     cur->parent = parent;
02865     cur->doc = parent->doc;
02866     if (parent->children == NULL) {
02867         parent->children = cur;
02868     parent->last = cur;
02869     } else {
02870         prev = parent->last;
02871     prev->next = cur;
02872     cur->prev = prev;
02873     parent->last = cur;
02874     }
02875 
02876     return(cur);
02877 }
02878 #endif /* LIBXML_TREE_ENABLED */
02879 
02893 static xmlNodePtr
02894 xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
02895     xmlAttrPtr attr;
02896 
02897     if (cur->type != XML_ATTRIBUTE_NODE)
02898         return(NULL);
02899 
02900     /* check if an attribute with the same name exists */
02901     if (prop->ns == NULL)
02902         attr = xmlHasNsProp(cur->parent, prop->name, NULL);
02903     else
02904         attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
02905 
02906     if (prop->doc != cur->doc) {
02907         xmlSetTreeDoc(prop, cur->doc);
02908     }
02909     prop->parent = cur->parent;
02910     prop->prev = prev;
02911     if (prev != NULL) {
02912         prop->next = prev->next;
02913         prev->next = prop;
02914         if (prop->next)
02915             prop->next->prev = prop;
02916     } else {
02917         prop->next = cur;
02918         cur->prev = prop;
02919     }
02920     if (prop->prev == NULL && prop->parent != NULL)
02921         prop->parent->properties = (xmlAttrPtr) prop;
02922     if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
02923         /* different instance, destroy it (attributes must be unique) */
02924         xmlRemoveProp((xmlAttrPtr) attr);
02925     }
02926     return prop;
02927 }
02928 
02943 xmlNodePtr
02944 xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
02945     if (cur == NULL) {
02946 #ifdef DEBUG_TREE
02947         xmlGenericError(xmlGenericErrorContext,
02948         "xmlAddNextSibling : cur == NULL\n");
02949 #endif
02950     return(NULL);
02951     }
02952     if (elem == NULL) {
02953 #ifdef DEBUG_TREE
02954         xmlGenericError(xmlGenericErrorContext,
02955         "xmlAddNextSibling : elem == NULL\n");
02956 #endif
02957     return(NULL);
02958     }
02959 
02960     if (cur == elem) {
02961 #ifdef DEBUG_TREE
02962         xmlGenericError(xmlGenericErrorContext,
02963         "xmlAddNextSibling : cur == elem\n");
02964 #endif
02965     return(NULL);
02966     }
02967 
02968     xmlUnlinkNode(elem);
02969 
02970     if (elem->type == XML_TEXT_NODE) {
02971     if (cur->type == XML_TEXT_NODE) {
02972         xmlNodeAddContent(cur, elem->content);
02973         xmlFreeNode(elem);
02974         return(cur);
02975     }
02976     if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
02977             (cur->name == cur->next->name)) {
02978         xmlChar *tmp;
02979 
02980         tmp = xmlStrdup(elem->content);
02981         tmp = xmlStrcat(tmp, cur->next->content);
02982         xmlNodeSetContent(cur->next, tmp);
02983         xmlFree(tmp);
02984         xmlFreeNode(elem);
02985         return(cur->next);
02986     }
02987     } else if (elem->type == XML_ATTRIBUTE_NODE) {
02988         return xmlAddPropSibling(cur, cur, elem);
02989     }
02990 
02991     if (elem->doc != cur->doc) {
02992     xmlSetTreeDoc(elem, cur->doc);
02993     }
02994     elem->parent = cur->parent;
02995     elem->prev = cur;
02996     elem->next = cur->next;
02997     cur->next = elem;
02998     if (elem->next != NULL)
02999     elem->next->prev = elem;
03000     if ((elem->parent != NULL) && (elem->parent->last == cur))
03001     elem->parent->last = elem;
03002     return(elem);
03003 }
03004 
03005 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
03006     defined(LIBXML_SCHEMAS_ENABLED)
03007 
03021 xmlNodePtr
03022 xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
03023     if (cur == NULL) {
03024 #ifdef DEBUG_TREE
03025         xmlGenericError(xmlGenericErrorContext,
03026         "xmlAddPrevSibling : cur == NULL\n");
03027 #endif
03028     return(NULL);
03029     }
03030     if (elem == NULL) {
03031 #ifdef DEBUG_TREE
03032         xmlGenericError(xmlGenericErrorContext,
03033         "xmlAddPrevSibling : elem == NULL\n");
03034 #endif
03035     return(NULL);
03036     }
03037 
03038     if (cur == elem) {
03039 #ifdef DEBUG_TREE
03040         xmlGenericError(xmlGenericErrorContext,
03041         "xmlAddPrevSibling : cur == elem\n");
03042 #endif
03043     return(NULL);
03044     }
03045 
03046     xmlUnlinkNode(elem);
03047 
03048     if (elem->type == XML_TEXT_NODE) {
03049     if (cur->type == XML_TEXT_NODE) {
03050         xmlChar *tmp;
03051 
03052         tmp = xmlStrdup(elem->content);
03053         tmp = xmlStrcat(tmp, cur->content);
03054         xmlNodeSetContent(cur, tmp);
03055         xmlFree(tmp);
03056         xmlFreeNode(elem);
03057         return(cur);
03058     }
03059     if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
03060             (cur->name == cur->prev->name)) {
03061         xmlNodeAddContent(cur->prev, elem->content);
03062         xmlFreeNode(elem);
03063         return(cur->prev);
03064     }
03065     } else if (elem->type == XML_ATTRIBUTE_NODE) {
03066         return xmlAddPropSibling(cur->prev, cur, elem);
03067     }
03068 
03069     if (elem->doc != cur->doc) {
03070     xmlSetTreeDoc(elem, cur->doc);
03071     }
03072     elem->parent = cur->parent;
03073     elem->next = cur;
03074     elem->prev = cur->prev;
03075     cur->prev = elem;
03076     if (elem->prev != NULL)
03077     elem->prev->next = elem;
03078     if ((elem->parent != NULL) && (elem->parent->children == cur)) {
03079         elem->parent->children = elem;
03080     }
03081     return(elem);
03082 }
03083 #endif /* LIBXML_TREE_ENABLED */
03084 
03097 xmlNodePtr
03098 xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
03099     xmlNodePtr parent;
03100 
03101     if (cur == NULL) {
03102 #ifdef DEBUG_TREE
03103         xmlGenericError(xmlGenericErrorContext,
03104         "xmlAddSibling : cur == NULL\n");
03105 #endif
03106     return(NULL);
03107     }
03108 
03109     if (elem == NULL) {
03110 #ifdef DEBUG_TREE
03111         xmlGenericError(xmlGenericErrorContext,
03112         "xmlAddSibling : elem == NULL\n");
03113 #endif
03114     return(NULL);
03115     }
03116 
03117     if (cur == elem) {
03118 #ifdef DEBUG_TREE
03119         xmlGenericError(xmlGenericErrorContext,
03120         "xmlAddSibling : cur == elem\n");
03121 #endif
03122     return(NULL);
03123     }
03124 
03125     /*
03126      * Constant time is we can rely on the ->parent->last to find
03127      * the last sibling.
03128      */
03129     if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
03130     (cur->parent->children != NULL) &&
03131     (cur->parent->last != NULL) &&
03132     (cur->parent->last->next == NULL)) {
03133     cur = cur->parent->last;
03134     } else {
03135     while (cur->next != NULL) cur = cur->next;
03136     }
03137 
03138     xmlUnlinkNode(elem);
03139 
03140     if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
03141         (cur->name == elem->name)) {
03142     xmlNodeAddContent(cur, elem->content);
03143     xmlFreeNode(elem);
03144     return(cur);
03145     } else if (elem->type == XML_ATTRIBUTE_NODE) {
03146         return xmlAddPropSibling(cur, cur, elem);
03147     }
03148 
03149     if (elem->doc != cur->doc) {
03150     xmlSetTreeDoc(elem, cur->doc);
03151     }
03152     parent = cur->parent;
03153     elem->prev = cur;
03154     elem->next = NULL;
03155     elem->parent = parent;
03156     cur->next = elem;
03157     if (parent != NULL)
03158     parent->last = elem;
03159 
03160     return(elem);
03161 }
03162 
03173 xmlNodePtr
03174 xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
03175     xmlNodePtr prev;
03176 
03177     if (parent == NULL) {
03178 #ifdef DEBUG_TREE
03179         xmlGenericError(xmlGenericErrorContext,
03180         "xmlAddChildList : parent == NULL\n");
03181 #endif
03182     return(NULL);
03183     }
03184 
03185     if (cur == NULL) {
03186 #ifdef DEBUG_TREE
03187         xmlGenericError(xmlGenericErrorContext,
03188         "xmlAddChildList : child == NULL\n");
03189 #endif
03190     return(NULL);
03191     }
03192 
03193     if ((cur->doc != NULL) && (parent->doc != NULL) &&
03194         (cur->doc != parent->doc)) {
03195 #ifdef DEBUG_TREE
03196     xmlGenericError(xmlGenericErrorContext,
03197         "Elements moved to a different document\n");
03198 #endif
03199     }
03200 
03201     /*
03202      * add the first element at the end of the children list.
03203      */
03204 
03205     if (parent->children == NULL) {
03206         parent->children = cur;
03207     } else {
03208     /*
03209      * If cur and parent->last both are TEXT nodes, then merge them.
03210      */
03211     if ((cur->type == XML_TEXT_NODE) &&
03212         (parent->last->type == XML_TEXT_NODE) &&
03213         (cur->name == parent->last->name)) {
03214         xmlNodeAddContent(parent->last, cur->content);
03215         /*
03216          * if it's the only child, nothing more to be done.
03217          */
03218         if (cur->next == NULL) {
03219         xmlFreeNode(cur);
03220         return(parent->last);
03221         }
03222         prev = cur;
03223         cur = cur->next;
03224         xmlFreeNode(prev);
03225     }
03226         prev = parent->last;
03227     prev->next = cur;
03228     cur->prev = prev;
03229     }
03230     while (cur->next != NULL) {
03231     cur->parent = parent;
03232     if (cur->doc != parent->doc) {
03233         xmlSetTreeDoc(cur, parent->doc);
03234     }
03235         cur = cur->next;
03236     }
03237     cur->parent = parent;
03238     /* the parent may not be linked to a doc ! */
03239     if (cur->doc != parent->doc) {
03240         xmlSetTreeDoc(cur, parent->doc);
03241     }
03242     parent->last = cur;
03243 
03244     return(cur);
03245 }
03246 
03259 xmlNodePtr
03260 xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
03261     xmlNodePtr prev;
03262 
03263     if (parent == NULL) {
03264 #ifdef DEBUG_TREE
03265         xmlGenericError(xmlGenericErrorContext,
03266         "xmlAddChild : parent == NULL\n");
03267 #endif
03268     return(NULL);
03269     }
03270 
03271     if (cur == NULL) {
03272 #ifdef DEBUG_TREE
03273         xmlGenericError(xmlGenericErrorContext,
03274         "xmlAddChild : child == NULL\n");
03275 #endif
03276     return(NULL);
03277     }
03278 
03279     if (parent == cur) {
03280 #ifdef DEBUG_TREE
03281         xmlGenericError(xmlGenericErrorContext,
03282         "xmlAddChild : parent == cur\n");
03283 #endif
03284     return(NULL);
03285     }
03286     /*
03287      * If cur is a TEXT node, merge its content with adjacent TEXT nodes
03288      * cur is then freed.
03289      */
03290     if (cur->type == XML_TEXT_NODE) {
03291     if ((parent->type == XML_TEXT_NODE) &&
03292         (parent->content != NULL) &&
03293         (parent->name == cur->name)) {
03294         xmlNodeAddContent(parent, cur->content);
03295         xmlFreeNode(cur);
03296         return(parent);
03297     }
03298     if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
03299         (parent->last->name == cur->name) &&
03300         (parent->last != cur)) {
03301         xmlNodeAddContent(parent->last, cur->content);
03302         xmlFreeNode(cur);
03303         return(parent->last);
03304     }
03305     }
03306 
03307     /*
03308      * add the new element at the end of the children list.
03309      */
03310     prev = cur->parent;
03311     cur->parent = parent;
03312     if (cur->doc != parent->doc) {
03313     xmlSetTreeDoc(cur, parent->doc);
03314     }
03315     /* this check prevents a loop on tree-traversions if a developer
03316      * tries to add a node to its parent multiple times
03317      */
03318     if (prev == parent)
03319     return(cur);
03320 
03321     /*
03322      * Coalescing
03323      */
03324     if ((parent->type == XML_TEXT_NODE) &&
03325     (parent->content != NULL) &&
03326     (parent != cur)) {
03327     xmlNodeAddContent(parent, cur->content);
03328     xmlFreeNode(cur);
03329     return(parent);
03330     }
03331     if (cur->type == XML_ATTRIBUTE_NODE) {
03332         if (parent->type != XML_ELEMENT_NODE)
03333             return(NULL);
03334     if (parent->properties != NULL) {
03335         /* check if an attribute with the same name exists */
03336         xmlAttrPtr lastattr;
03337 
03338         if (cur->ns == NULL)
03339         lastattr = xmlHasNsProp(parent, cur->name, NULL);
03340         else
03341         lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
03342         if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
03343         /* different instance, destroy it (attributes must be unique) */
03344             xmlUnlinkNode((xmlNodePtr) lastattr);
03345         xmlFreeProp(lastattr);
03346         }
03347         if (lastattr == (xmlAttrPtr) cur)
03348             return(cur);
03349 
03350     }
03351     if (parent->properties == NULL) {
03352         parent->properties = (xmlAttrPtr) cur;
03353     } else {
03354         /* find the end */
03355         xmlAttrPtr lastattr = parent->properties;
03356         while (lastattr->next != NULL) {
03357         lastattr = lastattr->next;
03358         }
03359         lastattr->next = (xmlAttrPtr) cur;
03360         ((xmlAttrPtr) cur)->prev = lastattr;
03361     }
03362     } else {
03363     if (parent->children == NULL) {
03364         parent->children = cur;
03365         parent->last = cur;
03366     } else {
03367         prev = parent->last;
03368         prev->next = cur;
03369         cur->prev = prev;
03370         parent->last = cur;
03371     }
03372     }
03373     return(cur);
03374 }
03375 
03383 xmlNodePtr
03384 xmlGetLastChild(xmlNodePtr parent) {
03385     if (parent == NULL) {
03386 #ifdef DEBUG_TREE
03387         xmlGenericError(xmlGenericErrorContext,
03388         "xmlGetLastChild : parent == NULL\n");
03389 #endif
03390     return(NULL);
03391     }
03392     return(parent->last);
03393 }
03394 
03395 #ifdef LIBXML_TREE_ENABLED
03396 /*
03397  * 5 interfaces from DOM ElementTraversal
03398  */
03399 
03412 unsigned long
03413 xmlChildElementCount(xmlNodePtr parent) {
03414     unsigned long ret = 0;
03415     xmlNodePtr cur = NULL;
03416 
03417     if (parent == NULL)
03418         return(0);
03419     switch (parent->type) {
03420         case XML_ELEMENT_NODE:
03421         case XML_ENTITY_NODE:
03422         case XML_DOCUMENT_NODE:
03423         case XML_HTML_DOCUMENT_NODE:
03424             cur = parent->children;
03425             break;
03426         default:
03427             return(0);
03428     }
03429     while (cur != NULL) {
03430         if (cur->type == XML_ELEMENT_NODE)
03431             ret++;
03432         cur = cur->next;
03433     }
03434     return(ret);
03435 }
03436 
03448 xmlNodePtr
03449 xmlFirstElementChild(xmlNodePtr parent) {
03450     xmlNodePtr cur = NULL;
03451 
03452     if (parent == NULL)
03453         return(NULL);
03454     switch (parent->type) {
03455         case XML_ELEMENT_NODE:
03456         case XML_ENTITY_NODE:
03457         case XML_DOCUMENT_NODE:
03458         case XML_HTML_DOCUMENT_NODE:
03459             cur = parent->children;
03460             break;
03461         default:
03462             return(NULL);
03463     }
03464     while (cur != NULL) {
03465         if (cur->type == XML_ELEMENT_NODE)
03466             return(cur);
03467         cur = cur->next;
03468     }
03469     return(NULL);
03470 }
03471 
03483 xmlNodePtr
03484 xmlLastElementChild(xmlNodePtr parent) {
03485     xmlNodePtr cur = NULL;
03486 
03487     if (parent == NULL)
03488         return(NULL);
03489     switch (parent->type) {
03490         case XML_ELEMENT_NODE:
03491         case XML_ENTITY_NODE:
03492         case XML_DOCUMENT_NODE:
03493         case XML_HTML_DOCUMENT_NODE:
03494             cur = parent->last;
03495             break;
03496         default:
03497             return(NULL);
03498     }
03499     while (cur != NULL) {
03500         if (cur->type == XML_ELEMENT_NODE)
03501             return(cur);
03502         cur = cur->prev;
03503     }
03504     return(NULL);
03505 }
03506 
03519 xmlNodePtr
03520 xmlPreviousElementSibling(xmlNodePtr node) {
03521     if (node == NULL)
03522         return(NULL);
03523     switch (node->type) {
03524         case XML_ELEMENT_NODE:
03525         case XML_TEXT_NODE:
03526         case XML_CDATA_SECTION_NODE:
03527         case XML_ENTITY_REF_NODE:
03528         case XML_ENTITY_NODE:
03529         case XML_PI_NODE:
03530         case XML_COMMENT_NODE:
03531         case XML_XINCLUDE_START:
03532         case XML_XINCLUDE_END:
03533             node = node->prev;
03534             break;
03535         default:
03536             return(NULL);
03537     }
03538     while (node != NULL) {
03539         if (node->type == XML_ELEMENT_NODE)
03540             return(node);
03541         node = node->prev;
03542     }
03543     return(NULL);
03544 }
03545 
03558 xmlNodePtr
03559 xmlNextElementSibling(xmlNodePtr node) {
03560     if (node == NULL)
03561         return(NULL);
03562     switch (node->type) {
03563         case XML_ELEMENT_NODE:
03564         case XML_TEXT_NODE:
03565         case XML_CDATA_SECTION_NODE:
03566         case XML_ENTITY_REF_NODE:
03567         case XML_ENTITY_NODE:
03568         case XML_PI_NODE:
03569         case XML_COMMENT_NODE:
03570         case XML_DTD_NODE:
03571         case XML_XINCLUDE_START:
03572         case XML_XINCLUDE_END:
03573             node = node->next;
03574             break;
03575         default:
03576             return(NULL);
03577     }
03578     while (node != NULL) {
03579         if (node->type == XML_ELEMENT_NODE)
03580             return(node);
03581         node = node->next;
03582     }
03583     return(NULL);
03584 }
03585 
03586 #endif /* LIBXML_TREE_ENABLED */
03587 
03595 void
03596 xmlFreeNodeList(xmlNodePtr cur) {
03597     xmlNodePtr next;
03598     xmlDictPtr dict = NULL;
03599 
03600     if (cur == NULL) return;
03601     if (cur->type == XML_NAMESPACE_DECL) {
03602     xmlFreeNsList((xmlNsPtr) cur);
03603     return;
03604     }
03605     if ((cur->type == XML_DOCUMENT_NODE) ||
03606 #ifdef LIBXML_DOCB_ENABLED
03607     (cur->type == XML_DOCB_DOCUMENT_NODE) ||
03608 #endif
03609     (cur->type == XML_HTML_DOCUMENT_NODE)) {
03610     xmlFreeDoc((xmlDocPtr) cur);
03611     return;
03612     }
03613     if (cur->doc != NULL) dict = cur->doc->dict;
03614     while (cur != NULL) {
03615         next = cur->next;
03616     if (cur->type != XML_DTD_NODE) {
03617 
03618         if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
03619         xmlDeregisterNodeDefaultValue(cur);
03620 
03621         if ((cur->children != NULL) &&
03622         (cur->type != XML_ENTITY_REF_NODE))
03623         xmlFreeNodeList(cur->children);
03624         if (((cur->type == XML_ELEMENT_NODE) ||
03625          (cur->type == XML_XINCLUDE_START) ||
03626          (cur->type == XML_XINCLUDE_END)) &&
03627         (cur->properties != NULL))
03628         xmlFreePropList(cur->properties);
03629         if ((cur->type != XML_ELEMENT_NODE) &&
03630         (cur->type != XML_XINCLUDE_START) &&
03631         (cur->type != XML_XINCLUDE_END) &&
03632         (cur->type != XML_ENTITY_REF_NODE) &&
03633         (cur->content != (xmlChar *) &(cur->properties))) {
03634         DICT_FREE(cur->content)
03635         }
03636         if (((cur->type == XML_ELEMENT_NODE) ||
03637              (cur->type == XML_XINCLUDE_START) ||
03638          (cur->type == XML_XINCLUDE_END)) &&
03639         (cur->nsDef != NULL))
03640         xmlFreeNsList(cur->nsDef);
03641 
03642         /*
03643          * When a node is a text node or a comment, it uses a global static
03644          * variable for the name of the node.
03645          * Otherwise the node name might come from the document's
03646          * dictionnary
03647          */
03648         if ((cur->name != NULL) &&
03649         (cur->type != XML_TEXT_NODE) &&
03650         (cur->type != XML_COMMENT_NODE))
03651         DICT_FREE(cur->name)
03652         xmlFree(cur);
03653     }
03654     cur = next;
03655     }
03656 }
03657 
03665 void
03666 xmlFreeNode(xmlNodePtr cur) {
03667     xmlDictPtr dict = NULL;
03668 
03669     if (cur == NULL) return;
03670 
03671     /* use xmlFreeDtd for DTD nodes */
03672     if (cur->type == XML_DTD_NODE) {
03673     xmlFreeDtd((xmlDtdPtr) cur);
03674     return;
03675     }
03676     if (cur->type == XML_NAMESPACE_DECL) {
03677     xmlFreeNs((xmlNsPtr) cur);
03678         return;
03679     }
03680     if (cur->type == XML_ATTRIBUTE_NODE) {
03681     xmlFreeProp((xmlAttrPtr) cur);
03682     return;
03683     }
03684 
03685     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
03686     xmlDeregisterNodeDefaultValue(cur);
03687 
03688     if (cur->doc != NULL) dict = cur->doc->dict;
03689 
03690     if (cur->type == XML_ENTITY_DECL) {
03691         xmlEntityPtr ent = (xmlEntityPtr) cur;
03692     DICT_FREE(ent->SystemID);
03693     DICT_FREE(ent->ExternalID);
03694     }
03695     if ((cur->children != NULL) &&
03696     (cur->type != XML_ENTITY_REF_NODE))
03697     xmlFreeNodeList(cur->children);
03698     if (((cur->type == XML_ELEMENT_NODE) ||
03699      (cur->type == XML_XINCLUDE_START) ||
03700      (cur->type == XML_XINCLUDE_END)) &&
03701     (cur->properties != NULL))
03702     xmlFreePropList(cur->properties);
03703     if ((cur->type != XML_ELEMENT_NODE) &&
03704     (cur->content != NULL) &&
03705     (cur->type != XML_ENTITY_REF_NODE) &&
03706     (cur->type != XML_XINCLUDE_END) &&
03707     (cur->type != XML_XINCLUDE_START) &&
03708     (cur->content != (xmlChar *) &(cur->properties))) {
03709     DICT_FREE(cur->content)
03710     }
03711 
03712     /*
03713      * When a node is a text node or a comment, it uses a global static
03714      * variable for the name of the node.
03715      * Otherwise the node name might come from the document's dictionnary
03716      */
03717     if ((cur->name != NULL) &&
03718         (cur->type != XML_TEXT_NODE) &&
03719         (cur->type != XML_COMMENT_NODE))
03720     DICT_FREE(cur->name)
03721 
03722     if (((cur->type == XML_ELEMENT_NODE) ||
03723      (cur->type == XML_XINCLUDE_START) ||
03724      (cur->type == XML_XINCLUDE_END)) &&
03725     (cur->nsDef != NULL))
03726     xmlFreeNsList(cur->nsDef);
03727     xmlFree(cur);
03728 }
03729 
03736 void
03737 xmlUnlinkNode(xmlNodePtr cur) {
03738     if (cur == NULL) {
03739 #ifdef DEBUG_TREE
03740         xmlGenericError(xmlGenericErrorContext,
03741         "xmlUnlinkNode : node == NULL\n");
03742 #endif
03743     return;
03744     }
03745     if (cur->type == XML_DTD_NODE) {
03746     xmlDocPtr doc;
03747     doc = cur->doc;
03748     if (doc != NULL) {
03749         if (doc->intSubset == (xmlDtdPtr) cur)
03750         doc->intSubset = NULL;
03751         if (doc->extSubset == (xmlDtdPtr) cur)
03752         doc->extSubset = NULL;
03753     }
03754     }
03755     if (cur->type == XML_ENTITY_DECL) {
03756         xmlDocPtr doc;
03757     doc = cur->doc;
03758     if (doc != NULL) {
03759         if (doc->intSubset != NULL) {
03760             if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
03761             xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
03762                                NULL);
03763             if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
03764             xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
03765                                NULL);
03766         }
03767         if (doc->extSubset != NULL) {
03768             if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
03769             xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
03770                                NULL);
03771             if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
03772             xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
03773                                NULL);
03774         }
03775     }
03776     }
03777     if (cur->parent != NULL) {
03778     xmlNodePtr parent;
03779     parent = cur->parent;
03780     if (cur->type == XML_ATTRIBUTE_NODE) {
03781         if (parent->properties == (xmlAttrPtr) cur)
03782         parent->properties = ((xmlAttrPtr) cur)->next;
03783     } else {
03784         if (parent->children == cur)
03785         parent->children = cur->next;
03786         if (parent->last == cur)
03787         parent->last = cur->prev;
03788     }
03789     cur->parent = NULL;
03790     }
03791     if (cur->next != NULL)
03792         cur->next->prev = cur->prev;
03793     if (cur->prev != NULL)
03794         cur->prev->next = cur->next;
03795     cur->next = cur->prev = NULL;
03796 }
03797 
03798 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
03799 
03810 xmlNodePtr
03811 xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
03812     if (old == cur) return(NULL);
03813     if ((old == NULL) || (old->parent == NULL)) {
03814 #ifdef DEBUG_TREE
03815         xmlGenericError(xmlGenericErrorContext,
03816         "xmlReplaceNode : old == NULL or without parent\n");
03817 #endif
03818     return(NULL);
03819     }
03820     if (cur == NULL) {
03821     xmlUnlinkNode(old);
03822     return(old);
03823     }
03824     if (cur == old) {
03825     return(old);
03826     }
03827     if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
03828 #ifdef DEBUG_TREE
03829         xmlGenericError(xmlGenericErrorContext,
03830         "xmlReplaceNode : Trying to replace attribute node with other node type\n");
03831 #endif
03832     return(old);
03833     }
03834     if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
03835 #ifdef DEBUG_TREE
03836         xmlGenericError(xmlGenericErrorContext,
03837         "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
03838 #endif
03839     return(old);
03840     }
03841     xmlUnlinkNode(cur);
03842     xmlSetTreeDoc(cur, old->doc);
03843     cur->parent = old->parent;
03844     cur->next = old->next;
03845     if (cur->next != NULL)
03846     cur->next->prev = cur;
03847     cur->prev = old->prev;
03848     if (cur->prev != NULL)
03849     cur->prev->next = cur;
03850     if (cur->parent != NULL) {
03851     if (cur->type == XML_ATTRIBUTE_NODE) {
03852         if (cur->parent->properties == (xmlAttrPtr)old)
03853         cur->parent->properties = ((xmlAttrPtr) cur);
03854     } else {
03855         if (cur->parent->children == old)
03856         cur->parent->children = cur;
03857         if (cur->parent->last == old)
03858         cur->parent->last = cur;
03859     }
03860     }
03861     old->next = old->prev = NULL;
03862     old->parent = NULL;
03863     return(old);
03864 }
03865 #endif /* LIBXML_TREE_ENABLED */
03866 
03867 /************************************************************************
03868  *                                  *
03869  *      Copy operations                     *
03870  *                                  *
03871  ************************************************************************/
03872 
03881 xmlNsPtr
03882 xmlCopyNamespace(xmlNsPtr cur) {
03883     xmlNsPtr ret;
03884 
03885     if (cur == NULL) return(NULL);
03886     switch (cur->type) {
03887     case XML_LOCAL_NAMESPACE:
03888         ret = xmlNewNs(NULL, cur->href, cur->prefix);
03889         break;
03890     default:
03891 #ifdef DEBUG_TREE
03892         xmlGenericError(xmlGenericErrorContext,
03893             "xmlCopyNamespace: invalid type %d\n", cur->type);
03894 #endif
03895         return(NULL);
03896     }
03897     return(ret);
03898 }
03899 
03908 xmlNsPtr
03909 xmlCopyNamespaceList(xmlNsPtr cur) {
03910     xmlNsPtr ret = NULL;
03911     xmlNsPtr p = NULL,q;
03912 
03913     while (cur != NULL) {
03914         q = xmlCopyNamespace(cur);
03915     if (p == NULL) {
03916         ret = p = q;
03917     } else {
03918         p->next = q;
03919         p = q;
03920     }
03921     cur = cur->next;
03922     }
03923     return(ret);
03924 }
03925 
03926 static xmlNodePtr
03927 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
03928 
03929 static xmlAttrPtr
03930 xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
03931     xmlAttrPtr ret;
03932 
03933     if (cur == NULL) return(NULL);
03934     if (target != NULL)
03935     ret = xmlNewDocProp(target->doc, cur->name, NULL);
03936     else if (doc != NULL)
03937     ret = xmlNewDocProp(doc, cur->name, NULL);
03938     else if (cur->parent != NULL)
03939     ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
03940     else if (cur->children != NULL)
03941     ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
03942     else
03943     ret = xmlNewDocProp(NULL, cur->name, NULL);
03944     if (ret == NULL) return(NULL);
03945     ret->parent = target;
03946 
03947     if ((cur->ns != NULL) && (target != NULL)) {
03948       xmlNsPtr ns;
03949 
03950       ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
03951       if (ns == NULL) {
03952         /*
03953          * Humm, we are copying an element whose namespace is defined
03954          * out of the new tree scope. Search it in the original tree
03955          * and add it at the top of the new tree
03956          */
03957         ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
03958         if (ns != NULL) {
03959           xmlNodePtr root = target;
03960           xmlNodePtr pred = NULL;
03961 
03962           while (root->parent != NULL) {
03963             pred = root;
03964             root = root->parent;
03965           }
03966           if (root == (xmlNodePtr) target->doc) {
03967             /* correct possibly cycling above the document elt */
03968             root = pred;
03969           }
03970           ret->ns = xmlNewNs(root, ns->href, ns->prefix);
03971         }
03972       } else {
03973         /*
03974          * we have to find something appropriate here since
03975          * we cant be sure, that the namespce we found is identified
03976          * by the prefix
03977          */
03978         if (xmlStrEqual(ns->href, cur->ns->href)) {
03979           /* this is the nice case */
03980           ret->ns = ns;
03981         } else {
03982           /*
03983            * we are in trouble: we need a new reconcilied namespace.
03984            * This is expensive
03985            */
03986           ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
03987         }
03988       }
03989 
03990     } else
03991         ret->ns = NULL;
03992 
03993     if (cur->children != NULL) {
03994     xmlNodePtr tmp;
03995 
03996     ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
03997     ret->last = NULL;
03998     tmp = ret->children;
03999     while (tmp != NULL) {
04000         /* tmp->parent = (xmlNodePtr)ret; */
04001         if (tmp->next == NULL)
04002             ret->last = tmp;
04003         tmp = tmp->next;
04004     }
04005     }
04006     /*
04007      * Try to handle IDs
04008      */
04009     if ((target!= NULL) && (cur!= NULL) &&
04010     (target->doc != NULL) && (cur->doc != NULL) &&
04011     (cur->doc->ids != NULL) && (cur->parent != NULL)) {
04012     if (xmlIsID(cur->doc, cur->parent, cur)) {
04013         xmlChar *id;
04014 
04015         id = xmlNodeListGetString(cur->doc, cur->children, 1);
04016         if (id != NULL) {
04017         xmlAddID(NULL, target->doc, id, ret);
04018         xmlFree(id);
04019         }
04020     }
04021     }
04022     return(ret);
04023 }
04024 
04034 xmlAttrPtr
04035 xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
04036     return xmlCopyPropInternal(NULL, target, cur);
04037 }
04038 
04048 xmlAttrPtr
04049 xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
04050     xmlAttrPtr ret = NULL;
04051     xmlAttrPtr p = NULL,q;
04052 
04053     while (cur != NULL) {
04054         q = xmlCopyProp(target, cur);
04055     if (q == NULL)
04056         return(NULL);
04057     if (p == NULL) {
04058         ret = p = q;
04059     } else {
04060         p->next = q;
04061         q->prev = p;
04062         p = q;
04063     }
04064     cur = cur->next;
04065     }
04066     return(ret);
04067 }
04068 
04069 /*
04070  * NOTE about the CopyNode operations !
04071  *
04072  * They are split into external and internal parts for one
04073  * tricky reason: namespaces. Doing a direct copy of a node
04074  * say RPM:Copyright without changing the namespace pointer to
04075  * something else can produce stale links. One way to do it is
04076  * to keep a reference counter but this doesn't work as soon
04077  * as one move the element or the subtree out of the scope of
04078  * the existing namespace. The actual solution seems to add
04079  * a copy of the namespace at the top of the copied tree if
04080  * not available in the subtree.
04081  * Hence two functions, the public front-end call the inner ones
04082  * The argument "recursive" normally indicates a recursive copy
04083  * of the node with values 0 (no) and 1 (yes).  For XInclude,
04084  * however, we allow a value of 2 to indicate copy properties and
04085  * namespace info, but don't recurse on children.
04086  */
04087 
04088 static xmlNodePtr
04089 xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
04090                   int extended) {
04091     xmlNodePtr ret;
04092 
04093     if (node == NULL) return(NULL);
04094     switch (node->type) {
04095         case XML_TEXT_NODE:
04096         case XML_CDATA_SECTION_NODE:
04097         case XML_ELEMENT_NODE:
04098         case XML_DOCUMENT_FRAG_NODE:
04099         case XML_ENTITY_REF_NODE:
04100         case XML_ENTITY_NODE:
04101         case XML_PI_NODE:
04102         case XML_COMMENT_NODE:
04103         case XML_XINCLUDE_START:
04104         case XML_XINCLUDE_END:
04105         break;
04106         case XML_ATTRIBUTE_NODE:
04107         return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
04108         case XML_NAMESPACE_DECL:
04109         return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
04110 
04111         case XML_DOCUMENT_NODE:
04112         case XML_HTML_DOCUMENT_NODE:
04113 #ifdef LIBXML_DOCB_ENABLED
04114         case XML_DOCB_DOCUMENT_NODE:
04115 #endif
04116 #ifdef LIBXML_TREE_ENABLED
04117         return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
04118 #endif /* LIBXML_TREE_ENABLED */
04119         case XML_DOCUMENT_TYPE_NODE:
04120         case XML_NOTATION_NODE:
04121         case XML_DTD_NODE:
04122         case XML_ELEMENT_DECL:
04123         case XML_ATTRIBUTE_DECL:
04124         case XML_ENTITY_DECL:
04125             return(NULL);
04126     }
04127 
04128     /*
04129      * Allocate a new node and fill the fields.
04130      */
04131     ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
04132     if (ret == NULL) {
04133     xmlTreeErrMemory("copying node");
04134     return(NULL);
04135     }
04136     memset(ret, 0, sizeof(xmlNode));
04137     ret->type = node->type;
04138 
04139     ret->doc = doc;
04140     ret->parent = parent;
04141     if (node->name == xmlStringText)
04142     ret->name = xmlStringText;
04143     else if (node->name == xmlStringTextNoenc)
04144     ret->name = xmlStringTextNoenc;
04145     else if (node->name == xmlStringComment)
04146     ret->name = xmlStringComment;
04147     else if (node->name != NULL) {
04148         if ((doc != NULL) && (doc->dict != NULL))
04149         ret->name = xmlDictLookup(doc->dict, node->name, -1);
04150     else
04151         ret->name = xmlStrdup(node->name);
04152     }
04153     if ((node->type != XML_ELEMENT_NODE) &&
04154     (node->content != NULL) &&
04155     (node->type != XML_ENTITY_REF_NODE) &&
04156     (node->type != XML_XINCLUDE_END) &&
04157     (node->type != XML_XINCLUDE_START)) {
04158     ret->content = xmlStrdup(node->content);
04159     }else{
04160       if (node->type == XML_ELEMENT_NODE)
04161         ret->line = node->line;
04162     }
04163     if (parent != NULL) {
04164     xmlNodePtr tmp;
04165 
04166     /*
04167      * this is a tricky part for the node register thing:
04168      * in case ret does get coalesced in xmlAddChild
04169      * the deregister-node callback is called; so we register ret now already
04170      */
04171     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
04172         xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
04173 
04174         tmp = xmlAddChild(parent, ret);
04175     /* node could have coalesced */
04176     if (tmp != ret)
04177         return(tmp);
04178     }
04179 
04180     if (!extended)
04181     goto out;
04182     if (((node->type == XML_ELEMENT_NODE) ||
04183          (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL))
04184         ret->nsDef = xmlCopyNamespaceList(node->nsDef);
04185 
04186     if (node->ns != NULL) {
04187         xmlNsPtr ns;
04188 
04189     ns = xmlSearchNs(doc, ret, node->ns->prefix);
04190     if (ns == NULL) {
04191         /*
04192          * Humm, we are copying an element whose namespace is defined
04193          * out of the new tree scope. Search it in the original tree
04194          * and add it at the top of the new tree
04195          */
04196         ns = xmlSearchNs(node->doc, node, node->ns->prefix);
04197         if (ns != NULL) {
04198             xmlNodePtr root = ret;
04199 
04200         while (root->parent != NULL) root = root->parent;
04201         ret->ns = xmlNewNs(root, ns->href, ns->prefix);
04202         } else {
04203             ret->ns = xmlNewReconciliedNs(doc, ret, node->ns);
04204         }
04205     } else {
04206         /*
04207          * reference the existing namespace definition in our own tree.
04208          */
04209         ret->ns = ns;
04210     }
04211     }
04212     if (((node->type == XML_ELEMENT_NODE) ||
04213          (node->type == XML_XINCLUDE_START)) && (node->properties != NULL))
04214         ret->properties = xmlCopyPropList(ret, node->properties);
04215     if (node->type == XML_ENTITY_REF_NODE) {
04216     if ((doc == NULL) || (node->doc != doc)) {
04217         /*
04218          * The copied node will go into a separate document, so
04219          * to avoid dangling references to the ENTITY_DECL node
04220          * we cannot keep the reference. Try to find it in the
04221          * target document.
04222          */
04223         ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
04224     } else {
04225             ret->children = node->children;
04226     }
04227     ret->last = ret->children;
04228     } else if ((node->children != NULL) && (extended != 2)) {
04229         ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
04230     UPDATE_LAST_CHILD_AND_PARENT(ret)
04231     }
04232 
04233 out:
04234     /* if parent != NULL we already registered the node above */
04235     if ((parent == NULL) &&
04236         ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
04237     xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
04238     return(ret);
04239 }
04240 
04241 static xmlNodePtr
04242 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
04243     xmlNodePtr ret = NULL;
04244     xmlNodePtr p = NULL,q;
04245 
04246     while (node != NULL) {
04247 #ifdef LIBXML_TREE_ENABLED
04248     if (node->type == XML_DTD_NODE ) {
04249         if (doc == NULL) {
04250         node = node->next;
04251         continue;
04252         }
04253         if (doc->intSubset == NULL) {
04254         q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
04255         q->doc = doc;
04256         q->parent = parent;
04257         doc->intSubset = (xmlDtdPtr) q;
04258         xmlAddChild(parent, q);
04259         } else {
04260         q = (xmlNodePtr) doc->intSubset;
04261         xmlAddChild(parent, q);
04262         }
04263     } else
04264 #endif /* LIBXML_TREE_ENABLED */
04265         q = xmlStaticCopyNode(node, doc, parent, 1);
04266     if (ret == NULL) {
04267         q->prev = NULL;
04268         ret = p = q;
04269     } else if (p != q) {
04270     /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
04271         p->next = q;
04272         q->prev = p;
04273         p = q;
04274     }
04275     node = node->next;
04276     }
04277     return(ret);
04278 }
04279 
04291 xmlNodePtr
04292 xmlCopyNode(const xmlNodePtr node, int extended) {
04293     xmlNodePtr ret;
04294 
04295     ret = xmlStaticCopyNode(node, NULL, NULL, extended);
04296     return(ret);
04297 }
04298 
04311 xmlNodePtr
04312 xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
04313     xmlNodePtr ret;
04314 
04315     ret = xmlStaticCopyNode(node, doc, NULL, extended);
04316     return(ret);
04317 }
04318 
04328 xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
04329     xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
04330     return(ret);
04331 }
04332 
04342 xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
04343     xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
04344     return(ret);
04345 }
04346 
04347 #if defined(LIBXML_TREE_ENABLED)
04348 
04356 xmlDtdPtr
04357 xmlCopyDtd(xmlDtdPtr dtd) {
04358     xmlDtdPtr ret;
04359     xmlNodePtr cur, p = NULL, q;
04360 
04361     if (dtd == NULL) return(NULL);
04362     ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
04363     if (ret == NULL) return(NULL);
04364     if (dtd->entities != NULL)
04365         ret->entities = (void *) xmlCopyEntitiesTable(
04366                         (xmlEntitiesTablePtr) dtd->entities);
04367     if (dtd->notations != NULL)
04368         ret->notations = (void *) xmlCopyNotationTable(
04369                         (xmlNotationTablePtr) dtd->notations);
04370     if (dtd->elements != NULL)
04371         ret->elements = (void *) xmlCopyElementTable(
04372                         (xmlElementTablePtr) dtd->elements);
04373     if (dtd->attributes != NULL)
04374         ret->attributes = (void *) xmlCopyAttributeTable(
04375                         (xmlAttributeTablePtr) dtd->attributes);
04376     if (dtd->pentities != NULL)
04377     ret->pentities = (void *) xmlCopyEntitiesTable(
04378                 (xmlEntitiesTablePtr) dtd->pentities);
04379 
04380     cur = dtd->children;
04381     while (cur != NULL) {
04382     q = NULL;
04383 
04384     if (cur->type == XML_ENTITY_DECL) {
04385         xmlEntityPtr tmp = (xmlEntityPtr) cur;
04386         switch (tmp->etype) {
04387         case XML_INTERNAL_GENERAL_ENTITY:
04388         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
04389         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
04390             q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
04391             break;
04392         case XML_INTERNAL_PARAMETER_ENTITY:
04393         case XML_EXTERNAL_PARAMETER_ENTITY:
04394             q = (xmlNodePtr)
04395             xmlGetParameterEntityFromDtd(ret, tmp->name);
04396             break;
04397         case XML_INTERNAL_PREDEFINED_ENTITY:
04398             break;
04399         }
04400     } else if (cur->type == XML_ELEMENT_DECL) {
04401         xmlElementPtr tmp = (xmlElementPtr) cur;
04402         q = (xmlNodePtr)
04403         xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
04404     } else if (cur->type == XML_ATTRIBUTE_DECL) {
04405         xmlAttributePtr tmp = (xmlAttributePtr) cur;
04406         q = (xmlNodePtr)
04407         xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
04408     } else if (cur->type == XML_COMMENT_NODE) {
04409         q = xmlCopyNode(cur, 0);
04410     }
04411 
04412     if (q == NULL) {
04413         cur = cur->next;
04414         continue;
04415     }
04416 
04417     if (p == NULL)
04418         ret->children = q;
04419     else
04420         p->next = q;
04421 
04422     q->prev = p;
04423     q->parent = (xmlNodePtr) ret;
04424     q->next = NULL;
04425     ret->last = q;
04426     p = q;
04427     cur = cur->next;
04428     }
04429 
04430     return(ret);
04431 }
04432 #endif
04433 
04434 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
04435 
04445 xmlDocPtr
04446 xmlCopyDoc(xmlDocPtr doc, int recursive) {
04447     xmlDocPtr ret;
04448 
04449     if (doc == NULL) return(NULL);
04450     ret = xmlNewDoc(doc->version);
04451     if (ret == NULL) return(NULL);
04452     if (doc->name != NULL)
04453         ret->name = xmlMemStrdup(doc->name);
04454     if (doc->encoding != NULL)
04455         ret->encoding = xmlStrdup(doc->encoding);
04456     if (doc->URL != NULL)
04457         ret->URL = xmlStrdup(doc->URL);
04458     ret->charset = doc->charset;
04459     ret->compression = doc->compression;
04460     ret->standalone = doc->standalone;
04461     if (!recursive) return(ret);
04462 
04463     ret->last = NULL;
04464     ret->children = NULL;
04465 #ifdef LIBXML_TREE_ENABLED
04466     if (doc->intSubset != NULL) {
04467         ret->intSubset = xmlCopyDtd(doc->intSubset);
04468     xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
04469     ret->intSubset->parent = ret;
04470     }
04471 #endif
04472     if (doc->oldNs != NULL)
04473         ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
04474     if (doc->children != NULL) {
04475     xmlNodePtr tmp;
04476 
04477     ret->children = xmlStaticCopyNodeList(doc->children, ret,
04478                                        (xmlNodePtr)ret);
04479     ret->last = NULL;
04480     tmp = ret->children;
04481     while (tmp != NULL) {
04482         if (tmp->next == NULL)
04483             ret->last = tmp;
04484         tmp = tmp->next;
04485     }
04486     }
04487     return(ret);
04488 }
04489 #endif /* LIBXML_TREE_ENABLED */
04490 
04491 /************************************************************************
04492  *                                  *
04493  *      Content access functions                *
04494  *                                  *
04495  ************************************************************************/
04496 
04506 long
04507 xmlGetLineNo(xmlNodePtr node)
04508 {
04509     long result = -1;
04510 
04511     if (!node)
04512         return result;
04513     if ((node->type == XML_ELEMENT_NODE) ||
04514         (node->type == XML_TEXT_NODE) ||
04515     (node->type == XML_COMMENT_NODE) ||
04516     (node->type == XML_PI_NODE))
04517         result = (long) node->line;
04518     else if ((node->prev != NULL) &&
04519              ((node->prev->type == XML_ELEMENT_NODE) ||
04520           (node->prev->type == XML_TEXT_NODE) ||
04521           (node->prev->type == XML_COMMENT_NODE) ||
04522           (node->prev->type == XML_PI_NODE)))
04523         result = xmlGetLineNo(node->prev);
04524     else if ((node->parent != NULL) &&
04525              (node->parent->type == XML_ELEMENT_NODE))
04526         result = xmlGetLineNo(node->parent);
04527 
04528     return result;
04529 }
04530 
04531 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
04532 
04541 xmlChar *
04542 xmlGetNodePath(xmlNodePtr node)
04543 {
04544     xmlNodePtr cur, tmp, next;
04545     xmlChar *buffer = NULL, *temp;
04546     size_t buf_len;
04547     xmlChar *buf;
04548     const char *sep;
04549     const char *name;
04550     char nametemp[100];
04551     int occur = 0, generic;
04552 
04553     if (node == NULL)
04554         return (NULL);
04555 
04556     buf_len = 500;
04557     buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
04558     if (buffer == NULL) {
04559     xmlTreeErrMemory("getting node path");
04560         return (NULL);
04561     }
04562     buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
04563     if (buf == NULL) {
04564     xmlTreeErrMemory("getting node path");
04565         xmlFree(buffer);
04566         return (NULL);
04567     }
04568 
04569     buffer[0] = 0;
04570     cur = node;
04571     do {
04572         name = "";
04573         sep = "?";
04574         occur = 0;
04575         if ((cur->type == XML_DOCUMENT_NODE) ||
04576             (cur->type == XML_HTML_DOCUMENT_NODE)) {
04577             if (buffer[0] == '/')
04578                 break;
04579             sep = "/";
04580             next = NULL;
04581         } else if (cur->type == XML_ELEMENT_NODE) {
04582         generic = 0;
04583             sep = "/";
04584             name = (const char *) cur->name;
04585             if (cur->ns) {
04586         if (cur->ns->prefix != NULL) {
04587                     snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
04588             (char *)cur->ns->prefix, (char *)cur->name);
04589             nametemp[sizeof(nametemp) - 1] = 0;
04590             name = nametemp;
04591         } else {
04592             /*
04593             * We cannot express named elements in the default
04594             * namespace, so use "*".
04595             */
04596             generic = 1;
04597             name = "*";
04598         }
04599             }
04600             next = cur->parent;
04601 
04602             /*
04603              * Thumbler index computation
04604          * TODO: the ocurence test seems bogus for namespaced names
04605              */
04606             tmp = cur->prev;
04607             while (tmp != NULL) {
04608                 if ((tmp->type == XML_ELEMENT_NODE) &&
04609             (generic ||
04610              (xmlStrEqual(cur->name, tmp->name) &&
04611              ((tmp->ns == cur->ns) ||
04612               ((tmp->ns != NULL) && (cur->ns != NULL) &&
04613                (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
04614                     occur++;
04615                 tmp = tmp->prev;
04616             }
04617             if (occur == 0) {
04618                 tmp = cur->next;
04619                 while (tmp != NULL && occur == 0) {
04620                     if ((tmp->type == XML_ELEMENT_NODE) &&
04621             (generic ||
04622              (xmlStrEqual(cur->name, tmp->name) &&
04623              ((tmp->ns == cur->ns) ||
04624               ((tmp->ns != NULL) && (cur->ns != NULL) &&
04625                (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
04626                         occur++;
04627                     tmp = tmp->next;
04628                 }
04629                 if (occur != 0)
04630                     occur = 1;
04631             } else
04632                 occur++;
04633         } else if (cur->type == XML_COMMENT_NODE) {
04634             sep = "/";
04635         name = "comment()";
04636             next = cur->parent;
04637 
04638             /*
04639              * Thumbler index computation
04640              */
04641             tmp = cur->prev;
04642             while (tmp != NULL) {
04643                 if (tmp->type == XML_COMMENT_NODE)
04644             occur++;
04645                 tmp = tmp->prev;
04646             }
04647             if (occur == 0) {
04648                 tmp = cur->next;
04649                 while (tmp != NULL && occur == 0) {
04650           if (tmp->type == XML_COMMENT_NODE)
04651             occur++;
04652                     tmp = tmp->next;
04653                 }
04654                 if (occur != 0)
04655                     occur = 1;
04656             } else
04657                 occur++;
04658         } else if ((cur->type == XML_TEXT_NODE) ||
04659                    (cur->type == XML_CDATA_SECTION_NODE)) {
04660             sep = "/";
04661         name = "text()";
04662             next = cur->parent;
04663 
04664             /*
04665              * Thumbler index computation
04666              */
04667             tmp = cur->prev;
04668             while (tmp != NULL) {
04669                 if ((tmp->type == XML_TEXT_NODE) ||
04670             (tmp->type == XML_CDATA_SECTION_NODE))
04671             occur++;
04672                 tmp = tmp->prev;
04673             }
04674         /*
04675         * Evaluate if this is the only text- or CDATA-section-node;
04676         * if yes, then we'll get "text()", otherwise "text()[1]".
04677         */
04678             if (occur == 0) {
04679                 tmp = cur->next;
04680                 while (tmp != NULL) {
04681             if ((tmp->type == XML_TEXT_NODE) ||
04682             (tmp->type == XML_CDATA_SECTION_NODE))
04683             {
04684             occur = 1;
04685             break;
04686             }
04687             tmp = tmp->next;
04688         }
04689             } else
04690                 occur++;
04691         } else if (cur->type == XML_PI_NODE) {
04692             sep = "/";
04693         snprintf(nametemp, sizeof(nametemp) - 1,
04694              "processing-instruction('%s')", (char *)cur->name);
04695             nametemp[sizeof(nametemp) - 1] = 0;
04696             name = nametemp;
04697 
04698         next = cur->parent;
04699 
04700             /*
04701              * Thumbler index computation
04702              */
04703             tmp = cur->prev;
04704             while (tmp != NULL) {
04705                 if ((tmp->type == XML_PI_NODE) &&
04706             (xmlStrEqual(cur->name, tmp->name)))
04707                     occur++;
04708                 tmp = tmp->prev;
04709             }
04710             if (occur == 0) {
04711                 tmp = cur->next;
04712                 while (tmp != NULL && occur == 0) {
04713                     if ((tmp->type == XML_PI_NODE) &&
04714             (xmlStrEqual(cur->name, tmp->name)))
04715                         occur++;
04716                     tmp = tmp->next;
04717                 }
04718                 if (occur != 0)
04719                     occur = 1;
04720             } else
04721                 occur++;
04722 
04723         } else if (cur->type == XML_ATTRIBUTE_NODE) {
04724             sep = "/@";
04725             name = (const char *) (((xmlAttrPtr) cur)->name);
04726             if (cur->ns) {
04727             if (cur->ns->prefix != NULL)
04728                     snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
04729             (char *)cur->ns->prefix, (char *)cur->name);
04730         else
04731             snprintf(nametemp, sizeof(nametemp) - 1, "%s",
04732             (char *)cur->name);
04733                 nametemp[sizeof(nametemp) - 1] = 0;
04734                 name = nametemp;
04735             }
04736             next = ((xmlAttrPtr) cur)->parent;
04737         } else {
04738             next = cur->parent;
04739         }
04740 
04741         /*
04742          * Make sure there is enough room
04743          */
04744         if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
04745             buf_len =
04746                 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
04747             temp = (xmlChar *) xmlRealloc(buffer, buf_len);
04748             if (temp == NULL) {
04749         xmlTreeErrMemory("getting node path");
04750                 xmlFree(buf);
04751                 xmlFree(buffer);
04752                 return (NULL);
04753             }
04754             buffer = temp;
04755             temp = (xmlChar *) xmlRealloc(buf, buf_len);
04756             if (temp == NULL) {
04757         xmlTreeErrMemory("getting node path");
04758                 xmlFree(buf);
04759                 xmlFree(buffer);
04760                 return (NULL);
04761             }
04762             buf = temp;
04763         }
04764         if (occur == 0)
04765             snprintf((char *) buf, buf_len, "%s%s%s",
04766                      sep, name, (char *) buffer);
04767         else
04768             snprintf((char *) buf, buf_len, "%s%s[%d]%s",
04769                      sep, name, occur, (char *) buffer);
04770         snprintf((char *) buffer, buf_len, "%s", (char *)buf);
04771         cur = next;
04772     } while (cur != NULL);
04773     xmlFree(buf);
04774     return (buffer);
04775 }
04776 #endif /* LIBXML_TREE_ENABLED */
04777 
04787 xmlNodePtr
04788 xmlDocGetRootElement(xmlDocPtr doc) {
04789     xmlNodePtr ret;
04790 
04791     if (doc == NULL) return(NULL);
04792     ret = doc->children;
04793     while (ret != NULL) {
04794     if (ret->type == XML_ELEMENT_NODE)
04795         return(ret);
04796         ret = ret->next;
04797     }
04798     return(ret);
04799 }
04800 
04801 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
04802 
04813 xmlNodePtr
04814 xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
04815     xmlNodePtr old = NULL;
04816 
04817     if (doc == NULL) return(NULL);
04818     if (root == NULL)
04819     return(NULL);
04820     xmlUnlinkNode(root);
04821     xmlSetTreeDoc(root, doc);
04822     root->parent = (xmlNodePtr) doc;
04823     old = doc->children;
04824     while (old != NULL) {
04825     if (old->type == XML_ELEMENT_NODE)
04826         break;
04827         old = old->next;
04828     }
04829     if (old == NULL) {
04830     if (doc->children == NULL) {
04831         doc->children = root;
04832         doc->last = root;
04833     } else {
04834         xmlAddSibling(doc->children, root);
04835     }
04836     } else {
04837     xmlReplaceNode(old, root);
04838     }
04839     return(old);
04840 }
04841 #endif
04842 
04843 #if defined(LIBXML_TREE_ENABLED)
04844 
04852 void
04853 xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
04854     xmlNsPtr ns;
04855 
04856     if (cur == NULL) return;
04857     switch(cur->type) {
04858         case XML_TEXT_NODE:
04859         case XML_CDATA_SECTION_NODE:
04860         case XML_COMMENT_NODE:
04861         case XML_DOCUMENT_NODE:
04862         case XML_DOCUMENT_TYPE_NODE:
04863         case XML_DOCUMENT_FRAG_NODE:
04864         case XML_NOTATION_NODE:
04865         case XML_HTML_DOCUMENT_NODE:
04866         case XML_DTD_NODE:
04867         case XML_ELEMENT_DECL:
04868         case XML_ATTRIBUTE_DECL:
04869         case XML_ENTITY_DECL:
04870         case XML_PI_NODE:
04871         case XML_ENTITY_REF_NODE:
04872         case XML_ENTITY_NODE:
04873     case XML_NAMESPACE_DECL:
04874 #ifdef LIBXML_DOCB_ENABLED
04875     case XML_DOCB_DOCUMENT_NODE:
04876 #endif
04877     case XML_XINCLUDE_START:
04878     case XML_XINCLUDE_END:
04879         return;
04880         case XML_ELEMENT_NODE:
04881         case XML_ATTRIBUTE_NODE:
04882         break;
04883     }
04884     ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
04885     if (ns == NULL)
04886     return;
04887     xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
04888 }
04889 #endif /* LIBXML_TREE_ENABLED */
04890 
04901 xmlChar *
04902 xmlNodeGetLang(xmlNodePtr cur) {
04903     xmlChar *lang;
04904 
04905     while (cur != NULL) {
04906         lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
04907     if (lang != NULL)
04908         return(lang);
04909     cur = cur->parent;
04910     }
04911     return(NULL);
04912 }
04913 
04914 
04915 #ifdef LIBXML_TREE_ENABLED
04916 
04924 void
04925 xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
04926     xmlNsPtr ns;
04927 
04928     if (cur == NULL) return;
04929     switch(cur->type) {
04930         case XML_TEXT_NODE:
04931         case XML_CDATA_SECTION_NODE:
04932         case XML_COMMENT_NODE:
04933         case XML_DOCUMENT_NODE:
04934         case XML_DOCUMENT_TYPE_NODE:
04935         case XML_DOCUMENT_FRAG_NODE:
04936         case XML_NOTATION_NODE:
04937         case XML_HTML_DOCUMENT_NODE:
04938         case XML_DTD_NODE:
04939         case XML_ELEMENT_DECL:
04940         case XML_ATTRIBUTE_DECL:
04941         case XML_ENTITY_DECL:
04942         case XML_PI_NODE:
04943         case XML_ENTITY_REF_NODE:
04944         case XML_ENTITY_NODE:
04945     case XML_NAMESPACE_DECL:
04946     case XML_XINCLUDE_START:
04947     case XML_XINCLUDE_END:
04948 #ifdef LIBXML_DOCB_ENABLED
04949     case XML_DOCB_DOCUMENT_NODE:
04950 #endif
04951         return;
04952         case XML_ELEMENT_NODE:
04953         case XML_ATTRIBUTE_NODE:
04954         break;
04955     }
04956     ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
04957     if (ns == NULL)
04958     return;
04959     switch (val) {
04960     case 0:
04961     xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
04962     break;
04963     case 1:
04964     xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
04965     break;
04966     }
04967 }
04968 #endif /* LIBXML_TREE_ENABLED */
04969 
04980 int
04981 xmlNodeGetSpacePreserve(xmlNodePtr cur) {
04982     xmlChar *space;
04983 
04984     while (cur != NULL) {
04985     space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
04986     if (space != NULL) {
04987         if (xmlStrEqual(space, BAD_CAST "preserve")) {
04988         xmlFree(space);
04989         return(1);
04990         }
04991         if (xmlStrEqual(space, BAD_CAST "default")) {
04992         xmlFree(space);
04993         return(0);
04994         }
04995         xmlFree(space);
04996     }
04997     cur = cur->parent;
04998     }
04999     return(-1);
05000 }
05001 
05002 #ifdef LIBXML_TREE_ENABLED
05003 
05010 void
05011 xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
05012     xmlDocPtr doc;
05013     xmlDictPtr dict;
05014 
05015     if (cur == NULL) return;
05016     if (name == NULL) return;
05017     switch(cur->type) {
05018         case XML_TEXT_NODE:
05019         case XML_CDATA_SECTION_NODE:
05020         case XML_COMMENT_NODE:
05021         case XML_DOCUMENT_TYPE_NODE:
05022         case XML_DOCUMENT_FRAG_NODE:
05023         case XML_NOTATION_NODE:
05024         case XML_HTML_DOCUMENT_NODE:
05025     case XML_NAMESPACE_DECL:
05026     case XML_XINCLUDE_START:
05027     case XML_XINCLUDE_END:
05028 #ifdef LIBXML_DOCB_ENABLED
05029     case XML_DOCB_DOCUMENT_NODE:
05030 #endif
05031         return;
05032         case XML_ELEMENT_NODE:
05033         case XML_ATTRIBUTE_NODE:
05034         case XML_PI_NODE:
05035         case XML_ENTITY_REF_NODE:
05036         case XML_ENTITY_NODE:
05037         case XML_DTD_NODE:
05038         case XML_DOCUMENT_NODE:
05039         case XML_ELEMENT_DECL:
05040         case XML_ATTRIBUTE_DECL:
05041         case XML_ENTITY_DECL:
05042         break;
05043     }
05044     doc = cur->doc;
05045     if (doc != NULL)
05046     dict = doc->dict;
05047     else
05048         dict = NULL;
05049     if (dict != NULL) {
05050         if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
05051         xmlFree((xmlChar *) cur->name);
05052     cur->name = xmlDictLookup(dict, name, -1);
05053     } else {
05054     if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
05055     cur->name = xmlStrdup(name);
05056     }
05057 }
05058 #endif
05059 
05060 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
05061 
05069 void
05070 xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
05071     xmlNsPtr ns;
05072     xmlChar* fixed;
05073 
05074     if (cur == NULL) return;
05075     switch(cur->type) {
05076         case XML_TEXT_NODE:
05077         case XML_CDATA_SECTION_NODE:
05078         case XML_COMMENT_NODE:
05079         case XML_DOCUMENT_TYPE_NODE:
05080         case XML_DOCUMENT_FRAG_NODE:
05081         case XML_NOTATION_NODE:
05082         case XML_DTD_NODE:
05083         case XML_ELEMENT_DECL:
05084         case XML_ATTRIBUTE_DECL:
05085         case XML_ENTITY_DECL:
05086         case XML_PI_NODE:
05087         case XML_ENTITY_REF_NODE:
05088         case XML_ENTITY_NODE:
05089     case XML_NAMESPACE_DECL:
05090     case XML_XINCLUDE_START:
05091     case XML_XINCLUDE_END:
05092         return;
05093         case XML_ELEMENT_NODE:
05094         case XML_ATTRIBUTE_NODE:
05095         break;
05096         case XML_DOCUMENT_NODE:
05097 #ifdef LIBXML_DOCB_ENABLED
05098     case XML_DOCB_DOCUMENT_NODE:
05099 #endif
05100         case XML_HTML_DOCUMENT_NODE: {
05101         xmlDocPtr doc = (xmlDocPtr) cur;
05102 
05103         if (doc->URL != NULL)
05104         xmlFree((xmlChar *) doc->URL);
05105         if (uri == NULL)
05106         doc->URL = NULL;
05107         else
05108         doc->URL = xmlPathToURI(uri);
05109         return;
05110     }
05111     }
05112 
05113     ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
05114     if (ns == NULL)
05115     return;
05116     fixed = xmlPathToURI(uri);
05117     if (fixed != NULL) {
05118     xmlSetNsProp(cur, ns, BAD_CAST "base", fixed);
05119     xmlFree(fixed);
05120     } else {
05121     xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
05122     }
05123 }
05124 #endif /* LIBXML_TREE_ENABLED */
05125 
05143 xmlChar *
05144 xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
05145     xmlChar *oldbase = NULL;
05146     xmlChar *base, *newbase;
05147 
05148     if ((cur == NULL) && (doc == NULL))
05149         return(NULL);
05150     if (doc == NULL) doc = cur->doc;
05151     if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
05152         cur = doc->children;
05153     while ((cur != NULL) && (cur->name != NULL)) {
05154         if (cur->type != XML_ELEMENT_NODE) {
05155             cur = cur->next;
05156         continue;
05157         }
05158         if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
05159             cur = cur->children;
05160         continue;
05161         }
05162         if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
05163             cur = cur->children;
05164         continue;
05165         }
05166         if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
05167                 return(xmlGetProp(cur, BAD_CAST "href"));
05168         }
05169         cur = cur->next;
05170     }
05171     return(NULL);
05172     }
05173     while (cur != NULL) {
05174     if (cur->type == XML_ENTITY_DECL) {
05175         xmlEntityPtr ent = (xmlEntityPtr) cur;
05176         return(xmlStrdup(ent->URI));
05177     }
05178     if (cur->type == XML_ELEMENT_NODE) {
05179         base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
05180         if (base != NULL) {
05181         if (oldbase != NULL) {
05182             newbase = xmlBuildURI(oldbase, base);
05183             if (newbase != NULL) {
05184             xmlFree(oldbase);
05185             xmlFree(base);
05186             oldbase = newbase;
05187             } else {
05188             xmlFree(oldbase);
05189             xmlFree(base);
05190             return(NULL);
05191             }
05192         } else {
05193             oldbase = base;
05194         }
05195         if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
05196             (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
05197             (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
05198             return(oldbase);
05199         }
05200     }
05201     cur = cur->parent;
05202     }
05203     if ((doc != NULL) && (doc->URL != NULL)) {
05204     if (oldbase == NULL)
05205         return(xmlStrdup(doc->URL));
05206     newbase = xmlBuildURI(oldbase, doc->URL);
05207     xmlFree(oldbase);
05208     return(newbase);
05209     }
05210     return(oldbase);
05211 }
05212 
05226 int
05227 xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
05228 {
05229     if ((cur == NULL) || (buffer == NULL)) return(-1);
05230     switch (cur->type) {
05231         case XML_CDATA_SECTION_NODE:
05232         case XML_TEXT_NODE:
05233         xmlBufferCat(buffer, cur->content);
05234             break;
05235         case XML_DOCUMENT_FRAG_NODE:
05236         case XML_ELEMENT_NODE:{
05237                 xmlNodePtr tmp = cur;
05238 
05239                 while (tmp != NULL) {
05240                     switch (tmp->type) {
05241                         case XML_CDATA_SECTION_NODE:
05242                         case XML_TEXT_NODE:
05243                             if (tmp->content != NULL)
05244                                 xmlBufferCat(buffer, tmp->content);
05245                             break;
05246                         case XML_ENTITY_REF_NODE:
05247                             xmlNodeBufGetContent(buffer, tmp);
05248                             break;
05249                         default:
05250                             break;
05251                     }
05252                     /*
05253                      * Skip to next node
05254                      */
05255                     if (tmp->children != NULL) {
05256                         if (tmp->children->type != XML_ENTITY_DECL) {
05257                             tmp = tmp->children;
05258                             continue;
05259                         }
05260                     }
05261                     if (tmp == cur)
05262                         break;
05263 
05264                     if (tmp->next != NULL) {
05265                         tmp = tmp->next;
05266                         continue;
05267                     }
05268 
05269                     do {
05270                         tmp = tmp->parent;
05271                         if (tmp == NULL)
05272                             break;
05273                         if (tmp == cur) {
05274                             tmp = NULL;
05275                             break;
05276                         }
05277                         if (tmp->next != NULL) {
05278                             tmp = tmp->next;
05279                             break;
05280                         }
05281                     } while (tmp != NULL);
05282                 }
05283         break;
05284             }
05285         case XML_ATTRIBUTE_NODE:{
05286                 xmlAttrPtr attr = (xmlAttrPtr) cur;
05287         xmlNodePtr tmp = attr->children;
05288 
05289         while (tmp != NULL) {
05290             if (tmp->type == XML_TEXT_NODE)
05291                 xmlBufferCat(buffer, tmp->content);
05292             else
05293                 xmlNodeBufGetContent(buffer, tmp);
05294             tmp = tmp->next;
05295         }
05296                 break;
05297             }
05298         case XML_COMMENT_NODE:
05299         case XML_PI_NODE:
05300         xmlBufferCat(buffer, cur->content);
05301             break;
05302         case XML_ENTITY_REF_NODE:{
05303                 xmlEntityPtr ent;
05304                 xmlNodePtr tmp;
05305 
05306                 /* lookup entity declaration */
05307                 ent = xmlGetDocEntity(cur->doc, cur->name);
05308                 if (ent == NULL)
05309                     return(-1);
05310 
05311                 /* an entity content can be any "well balanced chunk",
05312                  * i.e. the result of the content [43] production:
05313                  * http://www.w3.org/TR/REC-xml#NT-content
05314                  * -> we iterate through child nodes and recursive call
05315                  * xmlNodeGetContent() which handles all possible node types */
05316                 tmp = ent->children;
05317                 while (tmp) {
05318             xmlNodeBufGetContent(buffer, tmp);
05319                     tmp = tmp->next;
05320                 }
05321         break;
05322             }
05323         case XML_ENTITY_NODE:
05324         case XML_DOCUMENT_TYPE_NODE:
05325         case XML_NOTATION_NODE:
05326         case XML_DTD_NODE:
05327         case XML_XINCLUDE_START:
05328         case XML_XINCLUDE_END:
05329             break;
05330         case XML_DOCUMENT_NODE:
05331 #ifdef LIBXML_DOCB_ENABLED
05332         case XML_DOCB_DOCUMENT_NODE:
05333 #endif
05334         case XML_HTML_DOCUMENT_NODE:
05335         cur = cur->children;
05336         while (cur!= NULL) {
05337         if ((cur->type == XML_ELEMENT_NODE) ||
05338             (cur->type == XML_TEXT_NODE) ||
05339             (cur->type == XML_CDATA_SECTION_NODE)) {
05340             xmlNodeBufGetContent(buffer, cur);
05341         }
05342         cur = cur->next;
05343         }
05344         break;
05345         case XML_NAMESPACE_DECL:
05346         xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
05347         break;
05348         case XML_ELEMENT_DECL:
05349         case XML_ATTRIBUTE_DECL:
05350         case XML_ENTITY_DECL:
05351             break;
05352     }
05353     return(0);
05354 }
05366 xmlChar *
05367 xmlNodeGetContent(xmlNodePtr cur)
05368 {
05369     if (cur == NULL)
05370         return (NULL);
05371     switch (cur->type) {
05372         case XML_DOCUMENT_FRAG_NODE:
05373         case XML_ELEMENT_NODE:{
05374                 xmlBufferPtr buffer;
05375                 xmlChar *ret;
05376 
05377                 buffer = xmlBufferCreateSize(64);
05378                 if (buffer == NULL)
05379                     return (NULL);
05380         xmlNodeBufGetContent(buffer, cur);
05381                 ret = buffer->content;
05382                 buffer->content = NULL;
05383                 xmlBufferFree(buffer);
05384                 return (ret);
05385             }
05386         case XML_ATTRIBUTE_NODE:
05387         return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur));
05388         case XML_COMMENT_NODE:
05389         case XML_PI_NODE:
05390             if (cur->content != NULL)
05391                 return (xmlStrdup(cur->content));
05392             return (NULL);
05393         case XML_ENTITY_REF_NODE:{
05394                 xmlEntityPtr ent;
05395                 xmlBufferPtr buffer;
05396                 xmlChar *ret;
05397 
05398                 /* lookup entity declaration */
05399                 ent = xmlGetDocEntity(cur->doc, cur->name);
05400                 if (ent == NULL)
05401                     return (NULL);
05402 
05403                 buffer = xmlBufferCreate();
05404                 if (buffer == NULL)
05405                     return (NULL);
05406 
05407                 xmlNodeBufGetContent(buffer, cur);
05408 
05409                 ret = buffer->content;
05410                 buffer->content = NULL;
05411                 xmlBufferFree(buffer);
05412                 return (ret);
05413             }
05414         case XML_ENTITY_NODE:
05415         case XML_DOCUMENT_TYPE_NODE:
05416         case XML_NOTATION_NODE:
05417         case XML_DTD_NODE:
05418         case XML_XINCLUDE_START:
05419         case XML_XINCLUDE_END:
05420             return (NULL);
05421         case XML_DOCUMENT_NODE:
05422 #ifdef LIBXML_DOCB_ENABLED
05423         case XML_DOCB_DOCUMENT_NODE:
05424 #endif
05425         case XML_HTML_DOCUMENT_NODE: {
05426         xmlBufferPtr buffer;
05427         xmlChar *ret;
05428 
05429         buffer = xmlBufferCreate();
05430         if (buffer == NULL)
05431         return (NULL);
05432 
05433         xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
05434 
05435         ret = buffer->content;
05436         buffer->content = NULL;
05437         xmlBufferFree(buffer);
05438         return (ret);
05439     }
05440         case XML_NAMESPACE_DECL: {
05441         xmlChar *tmp;
05442 
05443         tmp = xmlStrdup(((xmlNsPtr) cur)->href);
05444             return (tmp);
05445     }
05446         case XML_ELEMENT_DECL:
05447             /* TODO !!! */
05448             return (NULL);
05449         case XML_ATTRIBUTE_DECL:
05450             /* TODO !!! */
05451             return (NULL);
05452         case XML_ENTITY_DECL:
05453             /* TODO !!! */
05454             return (NULL);
05455         case XML_CDATA_SECTION_NODE:
05456         case XML_TEXT_NODE:
05457             if (cur->content != NULL)
05458                 return (xmlStrdup(cur->content));
05459             return (NULL);
05460     }
05461     return (NULL);
05462 }
05463 
05474 void
05475 xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
05476     if (cur == NULL) {
05477 #ifdef DEBUG_TREE
05478         xmlGenericError(xmlGenericErrorContext,
05479         "xmlNodeSetContent : node == NULL\n");
05480 #endif
05481     return;
05482     }
05483     switch (cur->type) {
05484         case XML_DOCUMENT_FRAG_NODE:
05485         case XML_ELEMENT_NODE:
05486         case XML_ATTRIBUTE_NODE:
05487         if (cur->children != NULL) xmlFreeNodeList(cur->children);
05488         cur->children = xmlStringGetNodeList(cur->doc, content);
05489         UPDATE_LAST_CHILD_AND_PARENT(cur)
05490         break;
05491         case XML_TEXT_NODE:
05492         case XML_CDATA_SECTION_NODE:
05493         case XML_ENTITY_REF_NODE:
05494         case XML_ENTITY_NODE:
05495         case XML_PI_NODE:
05496         case XML_COMMENT_NODE:
05497         if ((cur->content != NULL) &&
05498             (cur->content != (xmlChar *) &(cur->properties))) {
05499             if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
05500             (xmlDictOwns(cur->doc->dict, cur->content))))
05501             xmlFree(cur->content);
05502         }
05503         if (cur->children != NULL) xmlFreeNodeList(cur->children);
05504         cur->last = cur->children = NULL;
05505         if (content != NULL) {
05506         cur->content = xmlStrdup(content);
05507         } else
05508         cur->content = NULL;
05509         cur->properties = NULL;
05510         cur->nsDef = NULL;
05511         break;
05512         case XML_DOCUMENT_NODE:
05513         case XML_HTML_DOCUMENT_NODE:
05514         case XML_DOCUMENT_TYPE_NODE:
05515     case XML_XINCLUDE_START:
05516     case XML_XINCLUDE_END:
05517 #ifdef LIBXML_DOCB_ENABLED
05518     case XML_DOCB_DOCUMENT_NODE:
05519 #endif
05520         break;
05521         case XML_NOTATION_NODE:
05522         break;
05523         case XML_DTD_NODE:
05524         break;
05525     case XML_NAMESPACE_DECL:
05526         break;
05527         case XML_ELEMENT_DECL:
05528         /* TODO !!! */
05529         break;
05530         case XML_ATTRIBUTE_DECL:
05531         /* TODO !!! */
05532         break;
05533         case XML_ENTITY_DECL:
05534         /* TODO !!! */
05535         break;
05536     }
05537 }
05538 
05539 #ifdef LIBXML_TREE_ENABLED
05540 
05551 void
05552 xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
05553     if (cur == NULL) {
05554 #ifdef DEBUG_TREE
05555         xmlGenericError(xmlGenericErrorContext,
05556         "xmlNodeSetContentLen : node == NULL\n");
05557 #endif
05558     return;
05559     }
05560     switch (cur->type) {
05561         case XML_DOCUMENT_FRAG_NODE:
05562         case XML_ELEMENT_NODE:
05563         case XML_ATTRIBUTE_NODE:
05564         if (cur->children != NULL) xmlFreeNodeList(cur->children);
05565         cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
05566         UPDATE_LAST_CHILD_AND_PARENT(cur)
05567         break;
05568         case XML_TEXT_NODE:
05569         case XML_CDATA_SECTION_NODE:
05570         case XML_ENTITY_REF_NODE:
05571         case XML_ENTITY_NODE:
05572         case XML_PI_NODE:
05573         case XML_COMMENT_NODE:
05574         case XML_NOTATION_NODE:
05575         if ((cur->content != NULL) &&
05576             (cur->content != (xmlChar *) &(cur->properties))) {
05577             if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
05578             (xmlDictOwns(cur->doc->dict, cur->content))))
05579             xmlFree(cur->content);
05580         }
05581         if (cur->children != NULL) xmlFreeNodeList(cur->children);
05582         cur->children = cur->last = NULL;
05583         if (content != NULL) {
05584         cur->content = xmlStrndup(content, len);
05585         } else
05586         cur->content = NULL;
05587         cur->properties = NULL;
05588         cur->nsDef = NULL;
05589         break;
05590         case XML_DOCUMENT_NODE:
05591         case XML_DTD_NODE:
05592         case XML_HTML_DOCUMENT_NODE:
05593         case XML_DOCUMENT_TYPE_NODE:
05594     case XML_NAMESPACE_DECL:
05595     case XML_XINCLUDE_START:
05596     case XML_XINCLUDE_END:
05597 #ifdef LIBXML_DOCB_ENABLED
05598     case XML_DOCB_DOCUMENT_NODE:
05599 #endif
05600         break;
05601         case XML_ELEMENT_DECL:
05602         /* TODO !!! */
05603         break;
05604         case XML_ATTRIBUTE_DECL:
05605         /* TODO !!! */
05606         break;
05607         case XML_ENTITY_DECL:
05608         /* TODO !!! */
05609         break;
05610     }
05611 }
05612 #endif /* LIBXML_TREE_ENABLED */
05613 
05625 void
05626 xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
05627     if (cur == NULL) {
05628 #ifdef DEBUG_TREE
05629         xmlGenericError(xmlGenericErrorContext,
05630         "xmlNodeAddContentLen : node == NULL\n");
05631 #endif
05632     return;
05633     }
05634     if (len <= 0) return;
05635     switch (cur->type) {
05636         case XML_DOCUMENT_FRAG_NODE:
05637         case XML_ELEMENT_NODE: {
05638         xmlNodePtr last, newNode, tmp;
05639 
05640         last = cur->last;
05641         newNode = xmlNewTextLen(content, len);
05642         if (newNode != NULL) {
05643         tmp = xmlAddChild(cur, newNode);
05644         if (tmp != newNode)
05645             return;
05646             if ((last != NULL) && (last->next == newNode)) {
05647             xmlTextMerge(last, newNode);
05648         }
05649         }
05650         break;
05651     }
05652         case XML_ATTRIBUTE_NODE:
05653         break;
05654         case XML_TEXT_NODE:
05655         case XML_CDATA_SECTION_NODE:
05656         case XML_ENTITY_REF_NODE:
05657         case XML_ENTITY_NODE:
05658         case XML_PI_NODE:
05659         case XML_COMMENT_NODE:
05660         case XML_NOTATION_NODE:
05661         if (content != NULL) {
05662             if ((cur->content == (xmlChar *) &(cur->properties)) ||
05663             ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
05664                 xmlDictOwns(cur->doc->dict, cur->content))) {
05665             cur->content = xmlStrncatNew(cur->content, content, len);
05666             cur->properties = NULL;
05667             cur->nsDef = NULL;
05668             break;
05669         }
05670         cur->content = xmlStrncat(cur->content, content, len);
05671             }
05672         case XML_DOCUMENT_NODE:
05673         case XML_DTD_NODE:
05674         case XML_HTML_DOCUMENT_NODE:
05675         case XML_DOCUMENT_TYPE_NODE:
05676     case XML_NAMESPACE_DECL:
05677     case XML_XINCLUDE_START:
05678     case XML_XINCLUDE_END:
05679 #ifdef LIBXML_DOCB_ENABLED
05680     case XML_DOCB_DOCUMENT_NODE:
05681 #endif
05682         break;
05683         case XML_ELEMENT_DECL:
05684         case XML_ATTRIBUTE_DECL:
05685         case XML_ENTITY_DECL:
05686         break;
05687     }
05688 }
05689 
05700 void
05701 xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
05702     int len;
05703 
05704     if (cur == NULL) {
05705 #ifdef DEBUG_TREE
05706         xmlGenericError(xmlGenericErrorContext,
05707         "xmlNodeAddContent : node == NULL\n");
05708 #endif
05709     return;
05710     }
05711     if (content == NULL) return;
05712     len = xmlStrlen(content);
05713     xmlNodeAddContentLen(cur, content, len);
05714 }
05715 
05724 xmlNodePtr
05725 xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
05726     if (first == NULL) return(second);
05727     if (second == NULL) return(first);
05728     if (first->type != XML_TEXT_NODE) return(first);
05729     if (second->type != XML_TEXT_NODE) return(first);
05730     if (second->name != first->name)
05731     return(first);
05732     xmlNodeAddContent(first, second->content);
05733     xmlUnlinkNode(second);
05734     xmlFreeNode(second);
05735     return(first);
05736 }
05737 
05738 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
05739 
05749 xmlNsPtr *
05750 xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
05751 {
05752     xmlNsPtr cur;
05753     xmlNsPtr *ret = NULL;
05754     int nbns = 0;
05755     int maxns = 10;
05756     int i;
05757 
05758     while (node != NULL) {
05759         if (node->type == XML_ELEMENT_NODE) {
05760             cur = node->nsDef;
05761             while (cur != NULL) {
05762                 if (ret == NULL) {
05763                     ret =
05764                         (xmlNsPtr *) xmlMalloc((maxns + 1) *
05765                                                sizeof(xmlNsPtr));
05766                     if (ret == NULL) {
05767             xmlTreeErrMemory("getting namespace list");
05768                         return (NULL);
05769                     }
05770                     ret[nbns] = NULL;
05771                 }
05772                 for (i = 0; i < nbns; i++) {
05773                     if ((cur->prefix == ret[i]->prefix) ||
05774                         (xmlStrEqual(cur->prefix, ret[i]->prefix)))
05775                         break;
05776                 }
05777                 if (i >= nbns) {
05778                     if (nbns >= maxns) {
05779                         maxns *= 2;
05780                         ret = (xmlNsPtr *) xmlRealloc(ret,
05781                                                       (maxns +
05782                                                        1) *
05783                                                       sizeof(xmlNsPtr));
05784                         if (ret == NULL) {
05785                 xmlTreeErrMemory("getting namespace list");
05786                             return (NULL);
05787                         }
05788                     }
05789                     ret[nbns++] = cur;
05790                     ret[nbns] = NULL;
05791                 }
05792 
05793                 cur = cur->next;
05794             }
05795         }
05796         node = node->parent;
05797     }
05798     return (ret);
05799 }
05800 #endif /* LIBXML_TREE_ENABLED */
05801 
05802 /*
05803 * xmlTreeEnsureXMLDecl:
05804 * @doc: the doc
05805 *
05806 * Ensures that there is an XML namespace declaration on the doc.
05807 *
05808 * Returns the XML ns-struct or NULL on API and internal errors.
05809 */
05810 static xmlNsPtr
05811 xmlTreeEnsureXMLDecl(xmlDocPtr doc)
05812 {
05813     if (doc == NULL)
05814     return (NULL);
05815     if (doc->oldNs != NULL)
05816     return (doc->oldNs);
05817     {
05818     xmlNsPtr ns;
05819     ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
05820     if (ns == NULL) {
05821         xmlTreeErrMemory(
05822         "allocating the XML namespace");
05823         return (NULL);
05824     }
05825     memset(ns, 0, sizeof(xmlNs));
05826     ns->type = XML_LOCAL_NAMESPACE;
05827     ns->href = xmlStrdup(XML_XML_NAMESPACE);
05828     ns->prefix = xmlStrdup((const xmlChar *)"xml");
05829     doc->oldNs = ns;
05830     return (ns);
05831     }
05832 }
05833 
05850 xmlNsPtr
05851 xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
05852 
05853     xmlNsPtr cur;
05854     xmlNodePtr orig = node;
05855 
05856     if (node == NULL) return(NULL);
05857     if ((nameSpace != NULL) &&
05858     (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
05859     if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
05860         /*
05861          * The XML-1.0 namespace is normally held on the root
05862          * element. In this case exceptionally create it on the
05863          * node element.
05864          */
05865         cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
05866         if (cur == NULL) {
05867         xmlTreeErrMemory("searching namespace");
05868         return(NULL);
05869         }
05870         memset(cur, 0, sizeof(xmlNs));
05871         cur->type = XML_LOCAL_NAMESPACE;
05872         cur->href = xmlStrdup(XML_XML_NAMESPACE);
05873         cur->prefix = xmlStrdup((const xmlChar *)"xml");
05874         cur->next = node->nsDef;
05875         node->nsDef = cur;
05876         return(cur);
05877     }
05878     if (doc == NULL) {
05879         doc = node->doc;
05880         if (doc == NULL)
05881         return(NULL);
05882     }
05883     /*
05884     * Return the XML namespace declaration held by the doc.
05885     */
05886     if (doc->oldNs == NULL)
05887         return(xmlTreeEnsureXMLDecl(doc));
05888     else
05889         return(doc->oldNs);
05890     }
05891     while (node != NULL) {
05892     if ((node->type == XML_ENTITY_REF_NODE) ||
05893         (node->type == XML_ENTITY_NODE) ||
05894         (node->type == XML_ENTITY_DECL))
05895         return(NULL);
05896     if (node->type == XML_ELEMENT_NODE) {
05897         cur = node->nsDef;
05898         while (cur != NULL) {
05899         if ((cur->prefix == NULL) && (nameSpace == NULL) &&
05900             (cur->href != NULL))
05901             return(cur);
05902         if ((cur->prefix != NULL) && (nameSpace != NULL) &&
05903             (cur->href != NULL) &&
05904             (xmlStrEqual(cur->prefix, nameSpace)))
05905             return(cur);
05906         cur = cur->next;
05907         }
05908         if (orig != node) {
05909             cur = node->ns;
05910             if (cur != NULL) {
05911             if ((cur->prefix == NULL) && (nameSpace == NULL) &&
05912                 (cur->href != NULL))
05913                 return(cur);
05914             if ((cur->prefix != NULL) && (nameSpace != NULL) &&
05915                 (cur->href != NULL) &&
05916                 (xmlStrEqual(cur->prefix, nameSpace)))
05917                 return(cur);
05918             }
05919         }
05920     }
05921     node = node->parent;
05922     }
05923     return(NULL);
05924 }
05925 
05938 static int
05939 xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
05940              xmlNodePtr ancestor, const xmlChar * prefix)
05941 {
05942     xmlNsPtr tst;
05943 
05944     while ((node != NULL) && (node != ancestor)) {
05945         if ((node->type == XML_ENTITY_REF_NODE) ||
05946             (node->type == XML_ENTITY_NODE) ||
05947             (node->type == XML_ENTITY_DECL))
05948             return (-1);
05949         if (node->type == XML_ELEMENT_NODE) {
05950             tst = node->nsDef;
05951             while (tst != NULL) {
05952                 if ((tst->prefix == NULL)
05953                     && (prefix == NULL))
05954                     return (0);
05955                 if ((tst->prefix != NULL)
05956                     && (prefix != NULL)
05957                     && (xmlStrEqual(tst->prefix, prefix)))
05958                     return (0);
05959                 tst = tst->next;
05960             }
05961         }
05962         node = node->parent;
05963     }
05964     if (node != ancestor)
05965         return (-1);
05966     return (1);
05967 }
05968 
05979 xmlNsPtr
05980 xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
05981 {
05982     xmlNsPtr cur;
05983     xmlNodePtr orig = node;
05984     int is_attr;
05985 
05986     if ((node == NULL) || (href == NULL))
05987         return (NULL);
05988     if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
05989         /*
05990          * Only the document can hold the XML spec namespace.
05991          */
05992         if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
05993             /*
05994              * The XML-1.0 namespace is normally held on the root
05995              * element. In this case exceptionally create it on the
05996              * node element.
05997              */
05998             cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
05999             if (cur == NULL) {
06000         xmlTreeErrMemory("searching namespace");
06001                 return (NULL);
06002             }
06003             memset(cur, 0, sizeof(xmlNs));
06004             cur->type = XML_LOCAL_NAMESPACE;
06005             cur->href = xmlStrdup(XML_XML_NAMESPACE);
06006             cur->prefix = xmlStrdup((const xmlChar *) "xml");
06007             cur->next = node->nsDef;
06008             node->nsDef = cur;
06009             return (cur);
06010         }
06011     if (doc == NULL) {
06012         doc = node->doc;
06013         if (doc == NULL)
06014         return(NULL);
06015     }
06016     /*
06017     * Return the XML namespace declaration held by the doc.
06018     */
06019     if (doc->oldNs == NULL)
06020         return(xmlTreeEnsureXMLDecl(doc));
06021     else
06022         return(doc->oldNs);
06023     }
06024     is_attr = (node->type == XML_ATTRIBUTE_NODE);
06025     while (node != NULL) {
06026         if ((node->type == XML_ENTITY_REF_NODE) ||
06027             (node->type == XML_ENTITY_NODE) ||
06028             (node->type == XML_ENTITY_DECL))
06029             return (NULL);
06030         if (node->type == XML_ELEMENT_NODE) {
06031             cur = node->nsDef;
06032             while (cur != NULL) {
06033                 if ((cur->href != NULL) && (href != NULL) &&
06034                     (xmlStrEqual(cur->href, href))) {
06035             if (((!is_attr) || (cur->prefix != NULL)) &&
06036                 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
06037             return (cur);
06038                 }
06039                 cur = cur->next;
06040             }
06041             if (orig != node) {
06042                 cur = node->ns;
06043                 if (cur != NULL) {
06044                     if ((cur->href != NULL) && (href != NULL) &&
06045                         (xmlStrEqual(cur->href, href))) {
06046             if (((!is_attr) || (cur->prefix != NULL)) &&
06047                     (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
06048                 return (cur);
06049                     }
06050                 }
06051             }
06052         }
06053         node = node->parent;
06054     }
06055     return (NULL);
06056 }
06057 
06071 static xmlNsPtr
06072 xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
06073     xmlNsPtr def;
06074     xmlChar prefix[50];
06075     int counter = 1;
06076 
06077     if (tree == NULL) {
06078 #ifdef DEBUG_TREE
06079         xmlGenericError(xmlGenericErrorContext,
06080         "xmlNewReconciliedNs : tree == NULL\n");
06081 #endif
06082     return(NULL);
06083     }
06084     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
06085 #ifdef DEBUG_TREE
06086         xmlGenericError(xmlGenericErrorContext,
06087         "xmlNewReconciliedNs : ns == NULL\n");
06088 #endif
06089     return(NULL);
06090     }
06091     /*
06092      * Search an existing namespace definition inherited.
06093      */
06094     def = xmlSearchNsByHref(doc, tree, ns->href);
06095     if (def != NULL)
06096         return(def);
06097 
06098     /*
06099      * Find a close prefix which is not already in use.
06100      * Let's strip namespace prefixes longer than 20 chars !
06101      */
06102     if (ns->prefix == NULL)
06103     snprintf((char *) prefix, sizeof(prefix), "default");
06104     else
06105     snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
06106 
06107     def = xmlSearchNs(doc, tree, prefix);
06108     while (def != NULL) {
06109         if (counter > 1000) return(NULL);
06110     if (ns->prefix == NULL)
06111         snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
06112     else
06113         snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
06114         (char *)ns->prefix, counter++);
06115     def = xmlSearchNs(doc, tree, prefix);
06116     }
06117 
06118     /*
06119      * OK, now we are ready to create a new one.
06120      */
06121     def = xmlNewNs(tree, ns->href, prefix);
06122     return(def);
06123 }
06124 
06125 #ifdef LIBXML_TREE_ENABLED
06126 
06140 int
06141 xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
06142     xmlNsPtr *oldNs = NULL;
06143     xmlNsPtr *newNs = NULL;
06144     int sizeCache = 0;
06145     int nbCache = 0;
06146 
06147     xmlNsPtr n;
06148     xmlNodePtr node = tree;
06149     xmlAttrPtr attr;
06150     int ret = 0, i;
06151 
06152     if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
06153     if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
06154     if (node->doc != doc) return(-1);
06155     while (node != NULL) {
06156         /*
06157      * Reconciliate the node namespace
06158      */
06159     if (node->ns != NULL) {
06160         /*
06161          * initialize the cache if needed
06162          */
06163         if (sizeCache == 0) {
06164         sizeCache = 10;
06165         oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
06166                            sizeof(xmlNsPtr));
06167         if (oldNs == NULL) {
06168             xmlTreeErrMemory("fixing namespaces");
06169             return(-1);
06170         }
06171         newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
06172                            sizeof(xmlNsPtr));
06173         if (newNs == NULL) {
06174             xmlTreeErrMemory("fixing namespaces");
06175             xmlFree(oldNs);
06176             return(-1);
06177         }
06178         }
06179         for (i = 0;i < nbCache;i++) {
06180             if (oldNs[i] == node->ns) {
06181             node->ns = newNs[i];
06182             break;
06183         }
06184         }
06185         if (i == nbCache) {
06186             /*
06187          * OK we need to recreate a new namespace definition
06188          */
06189         n = xmlNewReconciliedNs(doc, tree, node->ns);
06190         if (n != NULL) { /* :-( what if else ??? */
06191             /*
06192              * check if we need to grow the cache buffers.
06193              */
06194             if (sizeCache <= nbCache) {
06195                 sizeCache *= 2;
06196             oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
06197                                            sizeof(xmlNsPtr));
06198                 if (oldNs == NULL) {
06199                 xmlTreeErrMemory("fixing namespaces");
06200                 xmlFree(newNs);
06201                 return(-1);
06202             }
06203             newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
06204                                            sizeof(xmlNsPtr));
06205                 if (newNs == NULL) {
06206                 xmlTreeErrMemory("fixing namespaces");
06207                 xmlFree(oldNs);
06208                 return(-1);
06209             }
06210             }
06211             newNs[nbCache] = n;
06212             oldNs[nbCache++] = node->ns;
06213             node->ns = n;
06214                 }
06215         }
06216     }
06217     /*
06218      * now check for namespace hold by attributes on the node.
06219      */
06220     if (node->type == XML_ELEMENT_NODE) {
06221         attr = node->properties;
06222         while (attr != NULL) {
06223         if (attr->ns != NULL) {
06224             /*
06225              * initialize the cache if needed
06226              */
06227             if (sizeCache == 0) {
06228             sizeCache = 10;
06229             oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
06230                                sizeof(xmlNsPtr));
06231             if (oldNs == NULL) {
06232                 xmlTreeErrMemory("fixing namespaces");
06233                 return(-1);
06234             }
06235             newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
06236                                sizeof(xmlNsPtr));
06237             if (newNs == NULL) {
06238                 xmlTreeErrMemory("fixing namespaces");
06239                 xmlFree(oldNs);
06240                 return(-1);
06241             }
06242             }
06243             for (i = 0;i < nbCache;i++) {
06244             if (oldNs[i] == attr->ns) {
06245                 attr->ns = newNs[i];
06246                 break;
06247             }
06248             }
06249             if (i == nbCache) {
06250             /*
06251              * OK we need to recreate a new namespace definition
06252              */
06253             n = xmlNewReconciliedNs(doc, tree, attr->ns);
06254             if (n != NULL) { /* :-( what if else ??? */
06255                 /*
06256                  * check if we need to grow the cache buffers.
06257                  */
06258                 if (sizeCache <= nbCache) {
06259                 sizeCache *= 2;
06260                 oldNs = (xmlNsPtr *) xmlRealloc(oldNs,
06261                            sizeCache * sizeof(xmlNsPtr));
06262                 if (oldNs == NULL) {
06263                     xmlTreeErrMemory("fixing namespaces");
06264                     xmlFree(newNs);
06265                     return(-1);
06266                 }
06267                 newNs = (xmlNsPtr *) xmlRealloc(newNs,
06268                            sizeCache * sizeof(xmlNsPtr));
06269                 if (newNs == NULL) {
06270                     xmlTreeErrMemory("fixing namespaces");
06271                     xmlFree(oldNs);
06272                     return(-1);
06273                 }
06274                 }
06275                 newNs[nbCache] = n;
06276                 oldNs[nbCache++] = attr->ns;
06277                 attr->ns = n;
06278             }
06279             }
06280         }
06281         attr = attr->next;
06282         }
06283     }
06284 
06285     /*
06286      * Browse the full subtree, deep first
06287      */
06288         if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
06289         /* deep first */
06290         node = node->children;
06291     } else if ((node != tree) && (node->next != NULL)) {
06292         /* then siblings */
06293         node = node->next;
06294     } else if (node != tree) {
06295         /* go up to parents->next if needed */
06296         while (node != tree) {
06297             if (node->parent != NULL)
06298             node = node->parent;
06299         if ((node != tree) && (node->next != NULL)) {
06300             node = node->next;
06301             break;
06302         }
06303         if (node->parent == NULL) {
06304             node = NULL;
06305             break;
06306         }
06307         }
06308         /* exit condition */
06309         if (node == tree)
06310             node = NULL;
06311     } else
06312         break;
06313     }
06314     if (oldNs != NULL)
06315     xmlFree(oldNs);
06316     if (newNs != NULL)
06317     xmlFree(newNs);
06318     return(ret);
06319 }
06320 #endif /* LIBXML_TREE_ENABLED */
06321 
06322 static xmlAttrPtr
06323 xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
06324                const xmlChar *nsName, int useDTD)
06325 {
06326     xmlAttrPtr prop;
06327 
06328     if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
06329     return(NULL);
06330 
06331     if (node->properties != NULL) {
06332     prop = node->properties;
06333     if (nsName == NULL) {
06334         /*
06335         * We want the attr to be in no namespace.
06336         */
06337         do {
06338         if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
06339             return(prop);
06340         }
06341         prop = prop->next;
06342         } while (prop != NULL);
06343     } else {
06344         /*
06345         * We want the attr to be in the specified namespace.
06346         */
06347         do {
06348         if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
06349             ((prop->ns->href == nsName) ||
06350              xmlStrEqual(prop->ns->href, nsName)))
06351         {
06352             return(prop);
06353         }
06354         prop = prop->next;
06355         } while (prop != NULL);
06356     }
06357     }
06358 
06359 #ifdef LIBXML_TREE_ENABLED
06360     if (! useDTD)
06361     return(NULL);
06362     /*
06363      * Check if there is a default/fixed attribute declaration in
06364      * the internal or external subset.
06365      */
06366     if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
06367     xmlDocPtr doc = node->doc;
06368     xmlAttributePtr attrDecl = NULL;
06369     xmlChar *elemQName, *tmpstr = NULL;
06370 
06371     /*
06372     * We need the QName of the element for the DTD-lookup.
06373     */
06374     if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
06375         tmpstr = xmlStrdup(node->ns->prefix);
06376         tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
06377         tmpstr = xmlStrcat(tmpstr, node->name);
06378         if (tmpstr == NULL)
06379         return(NULL);
06380         elemQName = tmpstr;
06381     } else
06382         elemQName = (xmlChar *) node->name;
06383     if (nsName == NULL) {
06384         /*
06385         * The common and nice case: Attr in no namespace.
06386         */
06387         attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
06388         elemQName, name, NULL);
06389         if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
06390         attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
06391             elemQName, name, NULL);
06392         }
06393     } else {
06394         xmlNsPtr *nsList, *cur;
06395 
06396         /*
06397         * The ugly case: Search using the prefixes of in-scope
06398         * ns-decls corresponding to @nsName.
06399         */
06400         nsList = xmlGetNsList(node->doc, node);
06401         if (nsList == NULL) {
06402         if (tmpstr != NULL)
06403             xmlFree(tmpstr);
06404         return(NULL);
06405         }
06406         cur = nsList;
06407         while (*cur != NULL) {
06408         if (xmlStrEqual((*cur)->href, nsName)) {
06409             attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
06410             name, (*cur)->prefix);
06411             if (attrDecl)
06412             break;
06413             if (doc->extSubset != NULL) {
06414             attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
06415                 name, (*cur)->prefix);
06416             if (attrDecl)
06417                 break;
06418             }
06419         }
06420         cur++;
06421         }
06422         xmlFree(nsList);
06423     }
06424     if (tmpstr != NULL)
06425         xmlFree(tmpstr);
06426     /*
06427     * Only default/fixed attrs are relevant.
06428     */
06429     if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
06430         return((xmlAttrPtr) attrDecl);
06431     }
06432 #endif /* LIBXML_TREE_ENABLED */
06433     return(NULL);
06434 }
06435 
06436 static xmlChar*
06437 xmlGetPropNodeValueInternal(xmlAttrPtr prop)
06438 {
06439     if (prop == NULL)
06440     return(NULL);
06441     if (prop->type == XML_ATTRIBUTE_NODE) {
06442     /*
06443     * Note that we return at least the empty string.
06444     *   TODO: Do we really always want that?
06445     */
06446     if (prop->children != NULL) {
06447         if ((prop->children->next == NULL) &&
06448         ((prop->children->type == XML_TEXT_NODE) ||
06449         (prop->children->type == XML_CDATA_SECTION_NODE)))
06450         {
06451         /*
06452         * Optimization for the common case: only 1 text node.
06453         */
06454         return(xmlStrdup(prop->children->content));
06455         } else {
06456         xmlChar *ret;
06457 
06458         ret = xmlNodeListGetString(prop->doc, prop->children, 1);
06459         if (ret != NULL)
06460             return(ret);
06461         }
06462     }
06463     return(xmlStrdup((xmlChar *)""));
06464     } else if (prop->type == XML_ATTRIBUTE_DECL) {
06465     return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
06466     }
06467     return(NULL);
06468 }
06469 
06482 xmlAttrPtr
06483 xmlHasProp(xmlNodePtr node, const xmlChar *name) {
06484     xmlAttrPtr prop;
06485     xmlDocPtr doc;
06486 
06487     if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
06488         return(NULL);
06489     /*
06490      * Check on the properties attached to the node
06491      */
06492     prop = node->properties;
06493     while (prop != NULL) {
06494         if (xmlStrEqual(prop->name, name))  {
06495         return(prop);
06496         }
06497     prop = prop->next;
06498     }
06499     if (!xmlCheckDTD) return(NULL);
06500 
06501     /*
06502      * Check if there is a default declaration in the internal
06503      * or external subsets
06504      */
06505     doc =  node->doc;
06506     if (doc != NULL) {
06507         xmlAttributePtr attrDecl;
06508         if (doc->intSubset != NULL) {
06509         attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
06510         if ((attrDecl == NULL) && (doc->extSubset != NULL))
06511         attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
06512             if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
06513               /* return attribute declaration only if a default value is given
06514                  (that includes #FIXED declarations) */
06515         return((xmlAttrPtr) attrDecl);
06516     }
06517     }
06518     return(NULL);
06519 }
06520 
06537 xmlAttrPtr
06538 xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
06539 
06540     return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
06541 }
06542 
06559 xmlChar *
06560 xmlGetProp(xmlNodePtr node, const xmlChar *name) {
06561     xmlAttrPtr prop;
06562 
06563     prop = xmlHasProp(node, name);
06564     if (prop == NULL)
06565     return(NULL);
06566     return(xmlGetPropNodeValueInternal(prop));
06567 }
06568 
06584 xmlChar *
06585 xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
06586     xmlAttrPtr prop;
06587 
06588     prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
06589     if (prop == NULL)
06590     return(NULL);
06591     return(xmlGetPropNodeValueInternal(prop));
06592 }
06593 
06609 xmlChar *
06610 xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
06611     xmlAttrPtr prop;
06612 
06613     prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
06614     if (prop == NULL)
06615     return(NULL);
06616     return(xmlGetPropNodeValueInternal(prop));
06617 }
06618 
06619 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
06620 
06629 int
06630 xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
06631     xmlAttrPtr prop;
06632 
06633     prop = xmlGetPropNodeInternal(node, name, NULL, 0);
06634     if (prop == NULL)
06635     return(-1);
06636     xmlUnlinkNode((xmlNodePtr) prop);
06637     xmlFreeProp(prop);
06638     return(0);
06639 }
06640 
06650 int
06651 xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
06652     xmlAttrPtr prop;
06653 
06654     prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
06655     if (prop == NULL)
06656     return(-1);
06657     xmlUnlinkNode((xmlNodePtr) prop);
06658     xmlFreeProp(prop);
06659     return(0);
06660 }
06661 #endif
06662 
06663 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
06664 
06678 xmlAttrPtr
06679 xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
06680     int len;
06681     const xmlChar *nqname;
06682 
06683     if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
06684     return(NULL);
06685 
06686     /*
06687      * handle QNames
06688      */
06689     nqname = xmlSplitQName3(name, &len);
06690     if (nqname != NULL) {
06691         xmlNsPtr ns;
06692     xmlChar *prefix = xmlStrndup(name, len);
06693     ns = xmlSearchNs(node->doc, node, prefix);
06694     if (prefix != NULL)
06695         xmlFree(prefix);
06696     if (ns != NULL)
06697         return(xmlSetNsProp(node, ns, nqname, value));
06698     }
06699     return(xmlSetNsProp(node, NULL, name, value));
06700 }
06701 
06714 xmlAttrPtr
06715 xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
06716          const xmlChar *value)
06717 {
06718     xmlAttrPtr prop;
06719 
06720     if (ns && (ns->href == NULL))
06721     return(NULL);
06722     prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
06723     if (prop != NULL) {
06724     /*
06725     * Modify the attribute's value.
06726     */
06727     if (prop->atype == XML_ATTRIBUTE_ID) {
06728         xmlRemoveID(node->doc, prop);
06729         prop->atype = XML_ATTRIBUTE_ID;
06730     }
06731     if (prop->children != NULL)
06732         xmlFreeNodeList(prop->children);
06733     prop->children = NULL;
06734     prop->last = NULL;
06735     prop->ns = ns;
06736     if (value != NULL) {
06737         xmlNodePtr tmp;
06738 
06739         if(!xmlCheckUTF8(value)) {
06740             xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) node->doc,
06741                        NULL);
06742                 if (node->doc != NULL)
06743                     node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
06744         }
06745         prop->children = xmlNewDocText(node->doc, value);
06746         prop->last = NULL;
06747         tmp = prop->children;
06748         while (tmp != NULL) {
06749         tmp->parent = (xmlNodePtr) prop;
06750         if (tmp->next == NULL)
06751             prop->last = tmp;
06752         tmp = tmp->next;
06753         }
06754     }
06755     if (prop->atype == XML_ATTRIBUTE_ID)
06756         xmlAddID(NULL, node->doc, value, prop);
06757     return(prop);
06758     }
06759     /*
06760     * No equal attr found; create a new one.
06761     */
06762     return(xmlNewPropInternal(node, ns, name, value, 0));
06763 }
06764 
06765 #endif /* LIBXML_TREE_ENABLED */
06766 
06774 int
06775 xmlNodeIsText(xmlNodePtr node) {
06776     if (node == NULL) return(0);
06777 
06778     if (node->type == XML_TEXT_NODE) return(1);
06779     return(0);
06780 }
06781 
06791 int
06792 xmlIsBlankNode(xmlNodePtr node) {
06793     const xmlChar *cur;
06794     if (node == NULL) return(0);
06795 
06796     if ((node->type != XML_TEXT_NODE) &&
06797         (node->type != XML_CDATA_SECTION_NODE))
06798     return(0);
06799     if (node->content == NULL) return(1);
06800     cur = node->content;
06801     while (*cur != 0) {
06802     if (!IS_BLANK_CH(*cur)) return(0);
06803     cur++;
06804     }
06805 
06806     return(1);
06807 }
06808 
06820 int
06821 xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
06822     if (node == NULL) return(-1);
06823 
06824     if ((node->type != XML_TEXT_NODE) &&
06825         (node->type != XML_CDATA_SECTION_NODE) &&
06826     (node->type != XML_COMMENT_NODE) &&
06827     (node->type != XML_PI_NODE)) {
06828 #ifdef DEBUG_TREE
06829     xmlGenericError(xmlGenericErrorContext,
06830         "xmlTextConcat: node is not text nor CDATA\n");
06831 #endif
06832         return(-1);
06833     }
06834     /* need to check if content is currently in the dictionary */
06835     if ((node->content == (xmlChar *) &(node->properties)) ||
06836         ((node->doc != NULL) && (node->doc->dict != NULL) &&
06837         xmlDictOwns(node->doc->dict, node->content))) {
06838     node->content = xmlStrncatNew(node->content, content, len);
06839     } else {
06840         node->content = xmlStrncat(node->content, content, len);
06841     }
06842     node->properties = NULL;
06843     if (node->content == NULL)
06844         return(-1);
06845     return(0);
06846 }
06847 
06848 /************************************************************************
06849  *                                  *
06850  *          Output : to a FILE or in memory         *
06851  *                                  *
06852  ************************************************************************/
06853 
06860 xmlBufferPtr
06861 xmlBufferCreate(void) {
06862     xmlBufferPtr ret;
06863 
06864     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
06865     if (ret == NULL) {
06866     xmlTreeErrMemory("creating buffer");
06867         return(NULL);
06868     }
06869     ret->use = 0;
06870     ret->size = xmlDefaultBufferSize;
06871     ret->alloc = xmlBufferAllocScheme;
06872     ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
06873     if (ret->content == NULL) {
06874     xmlTreeErrMemory("creating buffer");
06875     xmlFree(ret);
06876         return(NULL);
06877     }
06878     ret->content[0] = 0;
06879     ret->contentIO = NULL;
06880     return(ret);
06881 }
06882 
06890 xmlBufferPtr
06891 xmlBufferCreateSize(size_t size) {
06892     xmlBufferPtr ret;
06893 
06894     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
06895     if (ret == NULL) {
06896     xmlTreeErrMemory("creating buffer");
06897         return(NULL);
06898     }
06899     ret->use = 0;
06900     ret->alloc = xmlBufferAllocScheme;
06901     ret->size = (size ? size+2 : 0);         /* +1 for ending null */
06902     if (ret->size){
06903         ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
06904         if (ret->content == NULL) {
06905         xmlTreeErrMemory("creating buffer");
06906             xmlFree(ret);
06907             return(NULL);
06908         }
06909         ret->content[0] = 0;
06910     } else
06911     ret->content = NULL;
06912     ret->contentIO = NULL;
06913     return(ret);
06914 }
06915 
06927 xmlBufferPtr
06928 xmlBufferCreateStatic(void *mem, size_t size) {
06929     xmlBufferPtr ret;
06930 
06931     if ((mem == NULL) || (size == 0))
06932         return(NULL);
06933 
06934     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
06935     if (ret == NULL) {
06936     xmlTreeErrMemory("creating buffer");
06937         return(NULL);
06938     }
06939     ret->use = size;
06940     ret->size = size;
06941     ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
06942     ret->content = (xmlChar *) mem;
06943     return(ret);
06944 }
06945 
06953 void
06954 xmlBufferSetAllocationScheme(xmlBufferPtr buf,
06955                              xmlBufferAllocationScheme scheme) {
06956     if (buf == NULL) {
06957 #ifdef DEBUG_BUFFER
06958         xmlGenericError(xmlGenericErrorContext,
06959         "xmlBufferSetAllocationScheme: buf == NULL\n");
06960 #endif
06961         return;
06962     }
06963     if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
06964         (buf->alloc == XML_BUFFER_ALLOC_IO)) return;
06965     if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
06966         (scheme == XML_BUFFER_ALLOC_EXACT) ||
06967         (scheme == XML_BUFFER_ALLOC_IMMUTABLE))
06968     buf->alloc = scheme;
06969 }
06970 
06978 void
06979 xmlBufferFree(xmlBufferPtr buf) {
06980     if (buf == NULL) {
06981 #ifdef DEBUG_BUFFER
06982         xmlGenericError(xmlGenericErrorContext,
06983         "xmlBufferFree: buf == NULL\n");
06984 #endif
06985     return;
06986     }
06987 
06988     if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
06989         (buf->contentIO != NULL)) {
06990         xmlFree(buf->contentIO);
06991     } else if ((buf->content != NULL) &&
06992         (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
06993         xmlFree(buf->content);
06994     }
06995     xmlFree(buf);
06996 }
06997 
07004 void
07005 xmlBufferEmpty(xmlBufferPtr buf) {
07006     if (buf == NULL) return;
07007     if (buf->content == NULL) return;
07008     buf->use = 0;
07009     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
07010         buf->content = BAD_CAST "";
07011     } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
07012                (buf->contentIO != NULL)) {
07013         size_t start_buf = buf->content - buf->contentIO;
07014 
07015     buf->size += start_buf;
07016         buf->content = buf->contentIO;
07017         buf->content[0] = 0;
07018     } else {
07019         buf->content[0] = 0;
07020     }
07021 }
07022 
07032 int
07033 xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
07034     if (buf == NULL) return(-1);
07035     if (len == 0) return(0);
07036     if (len > buf->use) return(-1);
07037 
07038     buf->use -= len;
07039     if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
07040         ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
07041     /*
07042      * we just move the content pointer, but also make sure
07043      * the perceived buffer size has shrinked accordingly
07044      */
07045         buf->content += len;
07046     buf->size -= len;
07047 
07048         /*
07049      * sometimes though it maybe be better to really shrink
07050      * on IO buffers
07051      */
07052     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
07053         size_t start_buf = buf->content - buf->contentIO;
07054         if (start_buf >= buf->size) {
07055         memmove(buf->contentIO, &buf->content[0], buf->use);
07056         buf->content = buf->contentIO;
07057         buf->content[buf->use] = 0;
07058         buf->size += start_buf;
07059         }
07060     }
07061     } else {
07062     memmove(buf->content, &buf->content[len], buf->use);
07063     buf->content[buf->use] = 0;
07064     }
07065     return(len);
07066 }
07067 
07077 int
07078 xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
07079     int size;
07080     xmlChar *newbuf;
07081 
07082     if (buf == NULL) return(-1);
07083 
07084     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
07085     if (len + buf->use < buf->size) return(0);
07086 
07087     /*
07088      * Windows has a BIG problem on realloc timing, so we try to double
07089      * the buffer size (if that's enough) (bug 146697)
07090      * Apparently BSD too, and it's probably best for linux too
07091      * On an embedded system this may be something to change
07092      */
07093 #if 1
07094     if (buf->size > len)
07095         size = buf->size * 2;
07096     else
07097         size = buf->use + len + 100;
07098 #else
07099     size = buf->use + len + 100;
07100 #endif
07101 
07102     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
07103         size_t start_buf = buf->content - buf->contentIO;
07104 
07105     newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
07106     if (newbuf == NULL) {
07107         xmlTreeErrMemory("growing buffer");
07108         return(-1);
07109     }
07110     buf->contentIO = newbuf;
07111     buf->content = newbuf + start_buf;
07112     } else {
07113     newbuf = (xmlChar *) xmlRealloc(buf->content, size);
07114     if (newbuf == NULL) {
07115         xmlTreeErrMemory("growing buffer");
07116         return(-1);
07117     }
07118     buf->content = newbuf;
07119     }
07120     buf->size = size;
07121     return(buf->size - buf->use);
07122 }
07123 
07132 int
07133 xmlBufferDump(FILE *file, xmlBufferPtr buf) {
07134     int ret;
07135 
07136     if (buf == NULL) {
07137 #ifdef DEBUG_BUFFER
07138         xmlGenericError(xmlGenericErrorContext,
07139         "xmlBufferDump: buf == NULL\n");
07140 #endif
07141     return(0);
07142     }
07143     if (buf->content == NULL) {
07144 #ifdef DEBUG_BUFFER
07145         xmlGenericError(xmlGenericErrorContext,
07146         "xmlBufferDump: buf->content == NULL\n");
07147 #endif
07148     return(0);
07149     }
07150     if (file == NULL)
07151     file = stdout;
07152     ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
07153     return(ret);
07154 }
07155 
07165 const xmlChar *
07166 xmlBufferContent(const xmlBufferPtr buf)
07167 {
07168     if(!buf)
07169         return NULL;
07170 
07171     return buf->content;
07172 }
07173 
07183 int
07184 xmlBufferLength(const xmlBufferPtr buf)
07185 {
07186     if(!buf)
07187         return 0;
07188 
07189     return buf->use;
07190 }
07191 
07201 int
07202 xmlBufferResize(xmlBufferPtr buf, unsigned int size)
07203 {
07204     unsigned int newSize;
07205     xmlChar* rebuf = NULL;
07206     size_t start_buf;
07207 
07208     if (buf == NULL)
07209         return(0);
07210 
07211     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
07212 
07213     /* Don't resize if we don't have to */
07214     if (size < buf->size)
07215         return 1;
07216 
07217     /* figure out new size */
07218     switch (buf->alloc){
07219     case XML_BUFFER_ALLOC_IO:
07220     case XML_BUFFER_ALLOC_DOUBLEIT:
07221         /*take care of empty case*/
07222         newSize = (buf->size ? buf->size*2 : size + 10);
07223         while (size > newSize) {
07224             if (newSize > UINT_MAX / 2) {
07225                 xmlTreeErrMemory("growing buffer");
07226                 return 0;
07227             }
07228             newSize *= 2;
07229         }
07230         break;
07231     case XML_BUFFER_ALLOC_EXACT:
07232         newSize = size+10;
07233         break;
07234     default:
07235         newSize = size+10;
07236         break;
07237     }
07238 
07239     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
07240         start_buf = buf->content - buf->contentIO;
07241 
07242         if (start_buf > newSize) {
07243         /* move data back to start */
07244         memmove(buf->contentIO, buf->content, buf->use);
07245         buf->content = buf->contentIO;
07246         buf->content[buf->use] = 0;
07247         buf->size += start_buf;
07248     } else {
07249         rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
07250         if (rebuf == NULL) {
07251         xmlTreeErrMemory("growing buffer");
07252         return 0;
07253         }
07254         buf->contentIO = rebuf;
07255         buf->content = rebuf + start_buf;
07256     }
07257     } else {
07258     if (buf->content == NULL) {
07259         rebuf = (xmlChar *) xmlMallocAtomic(newSize);
07260     } else if (buf->size - buf->use < 100) {
07261         rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
07262         } else {
07263         /*
07264          * if we are reallocating a buffer far from being full, it's
07265          * better to make a new allocation and copy only the used range
07266          * and free the old one.
07267          */
07268         rebuf = (xmlChar *) xmlMallocAtomic(newSize);
07269         if (rebuf != NULL) {
07270         memcpy(rebuf, buf->content, buf->use);
07271         xmlFree(buf->content);
07272         rebuf[buf->use] = 0;
07273         }
07274     }
07275     if (rebuf == NULL) {
07276         xmlTreeErrMemory("growing buffer");
07277         return 0;
07278     }
07279     buf->content = rebuf;
07280     }
07281     buf->size = newSize;
07282 
07283     return 1;
07284 }
07285 
07298 int
07299 xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
07300     unsigned int needSize;
07301 
07302     if ((str == NULL) || (buf == NULL)) {
07303     return -1;
07304     }
07305     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
07306     if (len < -1) {
07307 #ifdef DEBUG_BUFFER
07308         xmlGenericError(xmlGenericErrorContext,
07309         "xmlBufferAdd: len < 0\n");
07310 #endif
07311     return -1;
07312     }
07313     if (len == 0) return 0;
07314 
07315     if (len < 0)
07316         len = xmlStrlen(str);
07317 
07318     if (len < 0) return -1;
07319     if (len == 0) return 0;
07320 
07321     needSize = buf->use + len + 2;
07322     if (needSize > buf->size){
07323         if (!xmlBufferResize(buf, needSize)){
07324         xmlTreeErrMemory("growing buffer");
07325             return XML_ERR_NO_MEMORY;
07326         }
07327     }
07328 
07329     memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
07330     buf->use += len;
07331     buf->content[buf->use] = 0;
07332     return 0;
07333 }
07334 
07347 int
07348 xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
07349     unsigned int needSize;
07350 
07351     if (buf == NULL)
07352         return(-1);
07353     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
07354     if (str == NULL) {
07355 #ifdef DEBUG_BUFFER
07356         xmlGenericError(xmlGenericErrorContext,
07357         "xmlBufferAddHead: str == NULL\n");
07358 #endif
07359     return -1;
07360     }
07361     if (len < -1) {
07362 #ifdef DEBUG_BUFFER
07363         xmlGenericError(xmlGenericErrorContext,
07364         "xmlBufferAddHead: len < 0\n");
07365 #endif
07366     return -1;
07367     }
07368     if (len == 0) return 0;
07369 
07370     if (len < 0)
07371         len = xmlStrlen(str);
07372 
07373     if (len <= 0) return -1;
07374 
07375     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
07376         size_t start_buf = buf->content - buf->contentIO;
07377 
07378     if (start_buf > (unsigned int) len) {
07379         /*
07380          * We can add it in the space previously shrinked
07381          */
07382         buf->content -= len;
07383             memmove(&buf->content[0], str, len);
07384         buf->use += len;
07385         buf->size += len;
07386         return(0);
07387     }
07388     }
07389     needSize = buf->use + len + 2;
07390     if (needSize > buf->size){
07391         if (!xmlBufferResize(buf, needSize)){
07392         xmlTreeErrMemory("growing buffer");
07393             return XML_ERR_NO_MEMORY;
07394         }
07395     }
07396 
07397     memmove(&buf->content[len], &buf->content[0], buf->use);
07398     memmove(&buf->content[0], str, len);
07399     buf->use += len;
07400     buf->content[buf->use] = 0;
07401     return 0;
07402 }
07403 
07414 int
07415 xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
07416     if (buf == NULL)
07417         return(-1);
07418     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
07419     if (str == NULL) return -1;
07420     return xmlBufferAdd(buf, str, -1);
07421 }
07422 
07433 int
07434 xmlBufferCCat(xmlBufferPtr buf, const char *str) {
07435     const char *cur;
07436 
07437     if (buf == NULL)
07438         return(-1);
07439     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
07440     if (str == NULL) {
07441 #ifdef DEBUG_BUFFER
07442         xmlGenericError(xmlGenericErrorContext,
07443         "xmlBufferCCat: str == NULL\n");
07444 #endif
07445     return -1;
07446     }
07447     for (cur = str;*cur != 0;cur++) {
07448         if (buf->use  + 10 >= buf->size) {
07449             if (!xmlBufferResize(buf, buf->use+10)){
07450         xmlTreeErrMemory("growing buffer");
07451                 return XML_ERR_NO_MEMORY;
07452             }
07453         }
07454         buf->content[buf->use++] = *cur;
07455     }
07456     buf->content[buf->use] = 0;
07457     return 0;
07458 }
07459 
07468 void
07469 xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
07470     if (buf == NULL)
07471         return;
07472     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
07473     xmlBufferCat(buf, string);
07474 }
07475 
07484 void
07485 xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
07486     if (buf == NULL)
07487         return;
07488     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
07489     xmlBufferCCat(buf, string);
07490 }
07491 
07492 
07502 void
07503 xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
07504     const xmlChar *cur, *base;
07505     if (buf == NULL)
07506         return;
07507     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
07508     if (xmlStrchr(string, '\"')) {
07509         if (xmlStrchr(string, '\'')) {
07510 #ifdef DEBUG_BUFFER
07511         xmlGenericError(xmlGenericErrorContext,
07512  "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
07513 #endif
07514         xmlBufferCCat(buf, "\"");
07515             base = cur = string;
07516             while(*cur != 0){
07517                 if(*cur == '"'){
07518                     if (base != cur)
07519                         xmlBufferAdd(buf, base, cur - base);
07520                     xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
07521                     cur++;
07522                     base = cur;
07523                 }
07524                 else {
07525                     cur++;
07526                 }
07527             }
07528             if (base != cur)
07529                 xmlBufferAdd(buf, base, cur - base);
07530         xmlBufferCCat(buf, "\"");
07531     }
07532         else{
07533         xmlBufferCCat(buf, "\'");
07534             xmlBufferCat(buf, string);
07535         xmlBufferCCat(buf, "\'");
07536         }
07537     } else {
07538         xmlBufferCCat(buf, "\"");
07539         xmlBufferCat(buf, string);
07540         xmlBufferCCat(buf, "\"");
07541     }
07542 }
07543 
07544 
07552 int
07553 xmlGetDocCompressMode (xmlDocPtr doc) {
07554     if (doc == NULL) return(-1);
07555     return(doc->compression);
07556 }
07557 
07566 void
07567 xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
07568     if (doc == NULL) return;
07569     if (mode < 0) doc->compression = 0;
07570     else if (mode > 9) doc->compression = 9;
07571     else doc->compression = mode;
07572 }
07573 
07580 int
07581 xmlGetCompressMode(void)
07582 {
07583     return (xmlCompressMode);
07584 }
07585 
07593 void
07594 xmlSetCompressMode(int mode) {
07595     if (mode < 0) xmlCompressMode = 0;
07596     else if (mode > 9) xmlCompressMode = 9;
07597     else xmlCompressMode = mode;
07598 }
07599 
07600 #define XML_TREE_NSMAP_PARENT -1
07601 #define XML_TREE_NSMAP_XML -2
07602 #define XML_TREE_NSMAP_DOC -3
07603 #define XML_TREE_NSMAP_CUSTOM -4
07604 
07605 typedef struct xmlNsMapItem *xmlNsMapItemPtr;
07606 struct xmlNsMapItem {
07607     xmlNsMapItemPtr next;
07608     xmlNsMapItemPtr prev;
07609     xmlNsPtr oldNs; /* old ns decl reference */
07610     xmlNsPtr newNs; /* new ns decl reference */
07611     int shadowDepth; /* Shadowed at this depth */
07612     /*
07613     * depth:
07614     * >= 0 == @node's ns-decls
07615     * -1   == @parent's ns-decls
07616     * -2   == the doc->oldNs XML ns-decl
07617     * -3   == the doc->oldNs storage ns-decls
07618     * -4   == ns-decls provided via custom ns-handling
07619     */
07620     int depth;
07621 };
07622 
07623 typedef struct xmlNsMap *xmlNsMapPtr;
07624 struct xmlNsMap {
07625     xmlNsMapItemPtr first;
07626     xmlNsMapItemPtr last;
07627     xmlNsMapItemPtr pool;
07628 };
07629 
07630 #define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
07631 #define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
07632 #define XML_NSMAP_POP(m, i) \
07633     i = (m)->last; \
07634     (m)->last = (i)->prev; \
07635     if ((m)->last == NULL) \
07636     (m)->first = NULL; \
07637     else \
07638     (m)->last->next = NULL; \
07639     (i)->next = (m)->pool; \
07640     (m)->pool = i;
07641 
07642 /*
07643 * xmlDOMWrapNsMapFree:
07644 * @map: the ns-map
07645 *
07646 * Frees the ns-map
07647 */
07648 static void
07649 xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
07650 {
07651     xmlNsMapItemPtr cur, tmp;
07652 
07653     if (nsmap == NULL)
07654     return;
07655     cur = nsmap->pool;
07656     while (cur != NULL) {
07657     tmp = cur;
07658     cur = cur->next;
07659     xmlFree(tmp);
07660     }
07661     cur = nsmap->first;
07662     while (cur != NULL) {
07663     tmp = cur;
07664     cur = cur->next;
07665     xmlFree(tmp);
07666     }
07667     xmlFree(nsmap);
07668 }
07669 
07670 /*
07671 * xmlDOMWrapNsMapAddItem:
07672 * @map: the ns-map
07673 * @oldNs: the old ns-struct
07674 * @newNs: the new ns-struct
07675 * @depth: depth and ns-kind information
07676 *
07677 * Adds an ns-mapping item.
07678 */
07679 static xmlNsMapItemPtr
07680 xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position,
07681                xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
07682 {
07683     xmlNsMapItemPtr ret;
07684     xmlNsMapPtr map;
07685 
07686     if (nsmap == NULL)
07687     return(NULL);
07688     if ((position != -1) && (position != 0))
07689     return(NULL);
07690     map = *nsmap;
07691 
07692     if (map == NULL) {
07693     /*
07694     * Create the ns-map.
07695     */
07696     map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
07697     if (map == NULL) {
07698         xmlTreeErrMemory("allocating namespace map");
07699         return (NULL);
07700     }
07701     memset(map, 0, sizeof(struct xmlNsMap));
07702     *nsmap = map;
07703     }
07704 
07705     if (map->pool != NULL) {
07706     /*
07707     * Reuse an item from the pool.
07708     */
07709     ret = map->pool;
07710     map->pool = ret->next;
07711     memset(ret, 0, sizeof(struct xmlNsMapItem));
07712     } else {
07713     /*
07714     * Create a new item.
07715     */
07716     ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
07717     if (ret == NULL) {
07718         xmlTreeErrMemory("allocating namespace map item");
07719         return (NULL);
07720     }
07721     memset(ret, 0, sizeof(struct xmlNsMapItem));
07722     }
07723 
07724     if (map->first == NULL) {
07725     /*
07726     * First ever.
07727     */
07728     map->first = ret;
07729     map->last = ret;
07730     } else if (position == -1) {
07731     /*
07732     * Append.
07733     */
07734     ret->prev = map->last;
07735     map->last->next = ret;
07736     map->last = ret;
07737     } else if (position == 0) {
07738     /*
07739     * Set on first position.
07740     */
07741     map->first->prev = ret;
07742     ret->next = map->first;
07743     map->first = ret;
07744     } else
07745     return(NULL);
07746 
07747     ret->oldNs = oldNs;
07748     ret->newNs = newNs;
07749     ret->shadowDepth = -1;
07750     ret->depth = depth;
07751     return (ret);
07752 }
07753 
07754 /*
07755 * xmlDOMWrapStoreNs:
07756 * @doc: the doc
07757 * @nsName: the namespace name
07758 * @prefix: the prefix
07759 *
07760 * Creates or reuses an xmlNs struct on doc->oldNs with
07761 * the given prefix and namespace name.
07762 *
07763 * Returns the aquired ns struct or NULL in case of an API
07764 *         or internal error.
07765 */
07766 static xmlNsPtr
07767 xmlDOMWrapStoreNs(xmlDocPtr doc,
07768            const xmlChar *nsName,
07769            const xmlChar *prefix)
07770 {
07771     xmlNsPtr ns;
07772 
07773     if (doc == NULL)
07774     return (NULL);
07775     ns = xmlTreeEnsureXMLDecl(doc);
07776     if (ns == NULL)
07777     return (NULL);
07778     if (ns->next != NULL) {
07779     /* Reuse. */
07780     ns = ns->next;
07781     while (ns != NULL) {
07782         if (((ns->prefix == prefix) ||
07783         xmlStrEqual(ns->prefix, prefix)) &&
07784         xmlStrEqual(ns->href, nsName)) {
07785         return (ns);
07786         }
07787         if (ns->next == NULL)
07788         break;
07789         ns = ns->next;
07790     }
07791     }
07792     /* Create. */
07793     if (ns != NULL) {
07794         ns->next = xmlNewNs(NULL, nsName, prefix);
07795         return (ns->next);
07796     }
07797     return(NULL);
07798 }
07799 
07800 /*
07801 * xmlDOMWrapNewCtxt:
07802 *
07803 * Allocates and initializes a new DOM-wrapper context.
07804 *
07805 * Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
07806 */
07807 xmlDOMWrapCtxtPtr
07808 xmlDOMWrapNewCtxt(void)
07809 {
07810     xmlDOMWrapCtxtPtr ret;
07811 
07812     ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
07813     if (ret == NULL) {
07814     xmlTreeErrMemory("allocating DOM-wrapper context");
07815     return (NULL);
07816     }
07817     memset(ret, 0, sizeof(xmlDOMWrapCtxt));
07818     return (ret);
07819 }
07820 
07821 /*
07822 * xmlDOMWrapFreeCtxt:
07823 * @ctxt: the DOM-wrapper context
07824 *
07825 * Frees the DOM-wrapper context.
07826 */
07827 void
07828 xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
07829 {
07830     if (ctxt == NULL)
07831     return;
07832     if (ctxt->namespaceMap != NULL)
07833     xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap);
07834     /*
07835     * TODO: Store the namespace map in the context.
07836     */
07837     xmlFree(ctxt);
07838 }
07839 
07840 /*
07841 * xmlTreeLookupNsListByPrefix:
07842 * @nsList: a list of ns-structs
07843 * @prefix: the searched prefix
07844 *
07845 * Searches for a ns-decl with the given prefix in @nsList.
07846 *
07847 * Returns the ns-decl if found, NULL if not found and on
07848 *         API errors.
07849 */
07850 static xmlNsPtr
07851 xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
07852 {
07853     if (nsList == NULL)
07854     return (NULL);
07855     {
07856     xmlNsPtr ns;
07857     ns = nsList;
07858     do {
07859         if ((prefix == ns->prefix) ||
07860         xmlStrEqual(prefix, ns->prefix)) {
07861         return (ns);
07862         }
07863         ns = ns->next;
07864     } while (ns != NULL);
07865     }
07866     return (NULL);
07867 }
07868 
07869 /*
07870 *
07871 * xmlDOMWrapNSNormGatherInScopeNs:
07872 * @map: the namespace map
07873 * @node: the node to start with
07874 *
07875 * Puts in-scope namespaces into the ns-map.
07876 *
07877 * Returns 0 on success, -1 on API or internal errors.
07878 */
07879 static int
07880 xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
07881                 xmlNodePtr node)
07882 {
07883     xmlNodePtr cur;
07884     xmlNsPtr ns;
07885     xmlNsMapItemPtr mi;
07886     int shadowed;
07887 
07888     if ((map == NULL) || (*map != NULL))
07889     return (-1);
07890     /*
07891     * Get in-scope ns-decls of @parent.
07892     */
07893     cur = node;
07894     while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
07895     if (cur->type == XML_ELEMENT_NODE) {
07896         if (cur->nsDef != NULL) {
07897         ns = cur->nsDef;
07898         do {
07899             shadowed = 0;
07900             if (XML_NSMAP_NOTEMPTY(*map)) {
07901             /*
07902             * Skip shadowed prefixes.
07903             */
07904             XML_NSMAP_FOREACH(*map, mi) {
07905                 if ((ns->prefix == mi->newNs->prefix) ||
07906                 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
07907                 shadowed = 1;
07908                 break;
07909                 }
07910             }
07911             }
07912             /*
07913             * Insert mapping.
07914             */
07915             mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
07916             ns, XML_TREE_NSMAP_PARENT);
07917             if (mi == NULL)
07918             return (-1);
07919             if (shadowed)
07920             mi->shadowDepth = 0;
07921             ns = ns->next;
07922         } while (ns != NULL);
07923         }
07924     }
07925     cur = cur->parent;
07926     }
07927     return (0);
07928 }
07929 
07930 /*
07931 * XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
07932 * otherwise copy it, when it was in the source-dict.
07933 */
07934 #define XML_TREE_ADOPT_STR(str) \
07935     if (adoptStr && (str != NULL)) { \
07936     if (destDoc->dict) { \
07937         const xmlChar *old = str;   \
07938         str = xmlDictLookup(destDoc->dict, str, -1); \
07939         if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
07940             (!xmlDictOwns(sourceDoc->dict, old))) \
07941         xmlFree((char *)old); \
07942     } else if ((sourceDoc) && (sourceDoc->dict) && \
07943         xmlDictOwns(sourceDoc->dict, str)) { \
07944         str = BAD_CAST xmlStrdup(str); \
07945     } \
07946     }
07947 
07948 /*
07949 * XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
07950 * put it in dest-dict or copy it.
07951 */
07952 #define XML_TREE_ADOPT_STR_2(str) \
07953     if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
07954     (sourceDoc->dict != NULL) && \
07955     xmlDictOwns(sourceDoc->dict, cur->content)) { \
07956     if (destDoc->dict) \
07957         cur->content = (xmlChar *) \
07958         xmlDictLookup(destDoc->dict, cur->content, -1); \
07959     else \
07960         cur->content = xmlStrdup(BAD_CAST cur->content); \
07961     }
07962 
07963 /*
07964 * xmlDOMWrapNSNormAddNsMapItem2:
07965 *
07966 * For internal use. Adds a ns-decl mapping.
07967 *
07968 * Returns 0 on success, -1 on internal errors.
07969 */
07970 static int
07971 xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
07972             xmlNsPtr oldNs, xmlNsPtr newNs)
07973 {
07974     if (*list == NULL) {
07975     *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
07976     if (*list == NULL) {
07977         xmlTreeErrMemory("alloc ns map item");
07978         return(-1);
07979     }
07980     *size = 3;
07981     *number = 0;
07982     } else if ((*number) >= (*size)) {
07983     *size *= 2;
07984     *list = (xmlNsPtr *) xmlRealloc(*list,
07985         (*size) * 2 * sizeof(xmlNsPtr));
07986     if (*list == NULL) {
07987         xmlTreeErrMemory("realloc ns map item");
07988         return(-1);
07989     }
07990     }
07991     (*list)[2 * (*number)] = oldNs;
07992     (*list)[2 * (*number) +1] = newNs;
07993     (*number)++;
07994     return (0);
07995 }
07996 
07997 /*
07998 * xmlDOMWrapRemoveNode:
07999 * @ctxt: a DOM wrapper context
08000 * @doc: the doc
08001 * @node: the node to be removed.
08002 * @options: set of options, unused at the moment
08003 *
08004 * Unlinks the given node from its owner.
08005 * This will substitute ns-references to node->nsDef for
08006 * ns-references to doc->oldNs, thus ensuring the removed
08007 * branch to be autark wrt ns-references.
08008 *
08009 * NOTE: This function was not intensively tested.
08010 *
08011 * Returns 0 on success, 1 if the node is not supported,
08012 *         -1 on API and internal errors.
08013 */
08014 int
08015 xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
08016              xmlNodePtr node, int options ATTRIBUTE_UNUSED)
08017 {
08018     xmlNsPtr *list = NULL;
08019     int sizeList, nbList, i, j;
08020     xmlNsPtr ns;
08021 
08022     if ((node == NULL) || (doc == NULL) || (node->doc != doc))
08023     return (-1);
08024 
08025     /* TODO: 0 or -1 ? */
08026     if (node->parent == NULL)
08027     return (0);
08028 
08029     switch (node->type) {
08030     case XML_TEXT_NODE:
08031     case XML_CDATA_SECTION_NODE:
08032     case XML_ENTITY_REF_NODE:
08033     case XML_PI_NODE:
08034     case XML_COMMENT_NODE:
08035         xmlUnlinkNode(node);
08036         return (0);
08037     case XML_ELEMENT_NODE:
08038     case XML_ATTRIBUTE_NODE:
08039         break;
08040     default:
08041         return (1);
08042     }
08043     xmlUnlinkNode(node);
08044     /*
08045     * Save out-of-scope ns-references in doc->oldNs.
08046     */
08047     do {
08048     switch (node->type) {
08049         case XML_ELEMENT_NODE:
08050         if ((ctxt == NULL) && (node->nsDef != NULL)) {
08051             ns = node->nsDef;
08052             do {
08053             if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
08054                 &nbList, ns, ns) == -1)
08055                 goto internal_error;
08056             ns = ns->next;
08057             } while (ns != NULL);
08058         }
08059         /* No break on purpose. */
08060         case XML_ATTRIBUTE_NODE:
08061         if (node->ns != NULL) {
08062             /*
08063             * Find a mapping.
08064             */
08065             if (list != NULL) {
08066             for (i = 0, j = 0; i < nbList; i++, j += 2) {
08067                 if (node->ns == list[j]) {
08068                 node->ns = list[++j];
08069                 goto next_node;
08070                 }
08071             }
08072             }
08073             ns = NULL;
08074             if (ctxt != NULL) {
08075             /*
08076             * User defined.
08077             */
08078             } else {
08079             /*
08080             * Add to doc's oldNs.
08081             */
08082             ns = xmlDOMWrapStoreNs(doc, node->ns->href,
08083                 node->ns->prefix);
08084             if (ns == NULL)
08085                 goto internal_error;
08086             }
08087             if (ns != NULL) {
08088             /*
08089             * Add mapping.
08090             */
08091             if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
08092                 &nbList, node->ns, ns) == -1)
08093                 goto internal_error;
08094             }
08095             node->ns = ns;
08096         }
08097         if ((node->type == XML_ELEMENT_NODE) &&
08098             (node->properties != NULL)) {
08099             node = (xmlNodePtr) node->properties;
08100             continue;
08101         }
08102         break;
08103         default:
08104         goto next_sibling;
08105     }
08106 next_node:
08107     if ((node->type == XML_ELEMENT_NODE) &&
08108         (node->children != NULL)) {
08109         node = node->children;
08110         continue;
08111     }
08112 next_sibling:
08113     if (node == NULL)
08114         break;
08115     if (node->next != NULL)
08116         node = node->next;
08117     else {
08118         node = node->parent;
08119         goto next_sibling;
08120     }
08121     } while (node != NULL);
08122 
08123     if (list != NULL)
08124     xmlFree(list);
08125     return (0);
08126 
08127 internal_error:
08128     if (list != NULL)
08129     xmlFree(list);
08130     return (-1);
08131 }
08132 
08133 /*
08134 * xmlSearchNsByNamespaceStrict:
08135 * @doc: the document
08136 * @node: the start node
08137 * @nsName: the searched namespace name
08138 * @retNs: the resulting ns-decl
08139 * @prefixed: if the found ns-decl must have a prefix (for attributes)
08140 *
08141 * Dynamically searches for a ns-declaration which matches
08142 * the given @nsName in the ancestor-or-self axis of @node.
08143 *
08144 * Returns 1 if a ns-decl was found, 0 if not and -1 on API
08145 *         and internal errors.
08146 */
08147 static int
08148 xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
08149                  const xmlChar* nsName,
08150                  xmlNsPtr *retNs, int prefixed)
08151 {
08152     xmlNodePtr cur, prev = NULL, out = NULL;
08153     xmlNsPtr ns, prevns;
08154 
08155     if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
08156     return (-1);
08157 
08158     *retNs = NULL;
08159     if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
08160     *retNs = xmlTreeEnsureXMLDecl(doc);
08161     if (*retNs == NULL)
08162         return (-1);
08163     return (1);
08164     }
08165     cur = node;
08166     do {
08167     if (cur->type == XML_ELEMENT_NODE) {
08168         if (cur->nsDef != NULL) {
08169         for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
08170             if (prefixed && (ns->prefix == NULL))
08171             continue;
08172             if (prev != NULL) {
08173             /*
08174             * Check the last level of ns-decls for a
08175             * shadowing prefix.
08176             */
08177             prevns = prev->nsDef;
08178             do {
08179                 if ((prevns->prefix == ns->prefix) ||
08180                 ((prevns->prefix != NULL) &&
08181                 (ns->prefix != NULL) &&
08182                 xmlStrEqual(prevns->prefix, ns->prefix))) {
08183                 /*
08184                 * Shadowed.
08185                 */
08186                 break;
08187                 }
08188                 prevns = prevns->next;
08189             } while (prevns != NULL);
08190             if (prevns != NULL)
08191                 continue;
08192             }
08193             /*
08194             * Ns-name comparison.
08195             */
08196             if ((nsName == ns->href) ||
08197             xmlStrEqual(nsName, ns->href)) {
08198             /*
08199             * At this point the prefix can only be shadowed,
08200             * if we are the the (at least) 3rd level of
08201             * ns-decls.
08202             */
08203             if (out) {
08204                 int ret;
08205 
08206                 ret = xmlNsInScope(doc, node, prev, ns->prefix);
08207                 if (ret < 0)
08208                 return (-1);
08209                 /*
08210                 * TODO: Should we try to find a matching ns-name
08211                 * only once? This here keeps on searching.
08212                 * I think we should try further since, there might
08213                 * be an other matching ns-decl with an unshadowed
08214                 * prefix.
08215                 */
08216                 if (! ret)
08217                 continue;
08218             }
08219             *retNs = ns;
08220             return (1);
08221             }
08222         }
08223         out = prev;
08224         prev = cur;
08225         }
08226     } else if ((cur->type == XML_ENTITY_NODE) ||
08227             (cur->type == XML_ENTITY_DECL))
08228         return (0);
08229     cur = cur->parent;
08230     } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
08231     return (0);
08232 }
08233 
08234 /*
08235 * xmlSearchNsByPrefixStrict:
08236 * @doc: the document
08237 * @node: the start node
08238 * @prefix: the searched namespace prefix
08239 * @retNs: the resulting ns-decl
08240 *
08241 * Dynamically searches for a ns-declaration which matches
08242 * the given @nsName in the ancestor-or-self axis of @node.
08243 *
08244 * Returns 1 if a ns-decl was found, 0 if not and -1 on API
08245 *         and internal errors.
08246 */
08247 static int
08248 xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
08249               const xmlChar* prefix,
08250               xmlNsPtr *retNs)
08251 {
08252     xmlNodePtr cur;
08253     xmlNsPtr ns;
08254 
08255     if ((doc == NULL) || (node == NULL))
08256     return (-1);
08257 
08258     if (retNs)
08259     *retNs = NULL;
08260     if (IS_STR_XML(prefix)) {
08261     if (retNs) {
08262         *retNs = xmlTreeEnsureXMLDecl(doc);
08263         if (*retNs == NULL)
08264         return (-1);
08265     }
08266     return (1);
08267     }
08268     cur = node;
08269     do {
08270     if (cur->type == XML_ELEMENT_NODE) {
08271         if (cur->nsDef != NULL) {
08272         ns = cur->nsDef;
08273         do {
08274             if ((prefix == ns->prefix) ||
08275             xmlStrEqual(prefix, ns->prefix))
08276             {
08277             /*
08278             * Disabled namespaces, e.g. xmlns:abc="".
08279             */
08280             if (ns->href == NULL)
08281                 return(0);
08282             if (retNs)
08283                 *retNs = ns;
08284             return (1);
08285             }
08286             ns = ns->next;
08287         } while (ns != NULL);
08288         }
08289     } else if ((cur->type == XML_ENTITY_NODE) ||
08290             (cur->type == XML_ENTITY_DECL))
08291         return (0);
08292     cur = cur->parent;
08293     } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
08294     return (0);
08295 }
08296 
08297 /*
08298 * xmlDOMWrapNSNormDeclareNsForced:
08299 * @doc: the doc
08300 * @elem: the element-node to declare on
08301 * @nsName: the namespace-name of the ns-decl
08302 * @prefix: the preferred prefix of the ns-decl
08303 * @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
08304 *
08305 * Declares a new namespace on @elem. It tries to use the
08306 * given @prefix; if a ns-decl with the given prefix is already existent
08307 * on @elem, it will generate an other prefix.
08308 *
08309 * Returns 1 if a ns-decl was found, 0 if not and -1 on API
08310 *         and internal errors.
08311 */
08312 static xmlNsPtr
08313 xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
08314                 xmlNodePtr elem,
08315                 const xmlChar *nsName,
08316                 const xmlChar *prefix,
08317                 int checkShadow)
08318 {
08319 
08320     xmlNsPtr ret;
08321     char buf[50];
08322     const xmlChar *pref;
08323     int counter = 0;
08324     /*
08325     * Create a ns-decl on @anchor.
08326     */
08327     pref = prefix;
08328     while (1) {
08329     /*
08330     * Lookup whether the prefix is unused in elem's ns-decls.
08331     */
08332     if ((elem->nsDef != NULL) &&
08333         (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
08334         goto ns_next_prefix;
08335     if (checkShadow && elem->parent &&
08336         ((xmlNodePtr) elem->parent->doc != elem->parent)) {
08337         /*
08338         * Does it shadow ancestor ns-decls?
08339         */
08340         if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
08341         goto ns_next_prefix;
08342     }
08343     ret = xmlNewNs(NULL, nsName, pref);
08344     if (ret == NULL)
08345         return (NULL);
08346     if (elem->nsDef == NULL)
08347         elem->nsDef = ret;
08348     else {
08349         xmlNsPtr ns2 = elem->nsDef;
08350         while (ns2->next != NULL)
08351         ns2 = ns2->next;
08352         ns2->next = ret;
08353     }
08354     return (ret);
08355 ns_next_prefix:
08356     counter++;
08357     if (counter > 1000)
08358         return (NULL);
08359     if (prefix == NULL) {
08360         snprintf((char *) buf, sizeof(buf),
08361         "ns_%d", counter);
08362     } else
08363         snprintf((char *) buf, sizeof(buf),
08364         "%.30s_%d", (char *)prefix, counter);
08365     pref = BAD_CAST buf;
08366     }
08367 }
08368 
08369 /*
08370 * xmlDOMWrapNSNormAquireNormalizedNs:
08371 * @doc: the doc
08372 * @elem: the element-node to declare namespaces on
08373 * @ns: the ns-struct to use for the search
08374 * @retNs: the found/created ns-struct
08375 * @nsMap: the ns-map
08376 * @depth: the current tree depth
08377 * @ancestorsOnly: search in ancestor ns-decls only
08378 * @prefixed: if the searched ns-decl must have a prefix (for attributes)
08379 *
08380 * Searches for a matching ns-name in the ns-decls of @nsMap, if not
08381 * found it will either declare it on @elem, or store it in doc->oldNs.
08382 * If a new ns-decl needs to be declared on @elem, it tries to use the
08383 * @ns->prefix for it, if this prefix is already in use on @elem, it will
08384 * change the prefix or the new ns-decl.
08385 *
08386 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
08387 */
08388 static int
08389 xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
08390                    xmlNodePtr elem,
08391                    xmlNsPtr ns,
08392                    xmlNsPtr *retNs,
08393                    xmlNsMapPtr *nsMap,
08394 
08395                    int depth,
08396                    int ancestorsOnly,
08397                    int prefixed)
08398 {
08399     xmlNsMapItemPtr mi;
08400 
08401     if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
08402     (nsMap == NULL))
08403     return (-1);
08404 
08405     *retNs = NULL;
08406     /*
08407     * Handle XML namespace.
08408     */
08409     if (IS_STR_XML(ns->prefix)) {
08410     /*
08411     * Insert XML namespace mapping.
08412     */
08413     *retNs = xmlTreeEnsureXMLDecl(doc);
08414     if (*retNs == NULL)
08415         return (-1);
08416     return (0);
08417     }
08418     /*
08419     * If the search should be done in ancestors only and no
08420     * @elem (the first ancestor) was specified, then skip the search.
08421     */
08422     if ((XML_NSMAP_NOTEMPTY(*nsMap)) &&
08423     (! (ancestorsOnly && (elem == NULL))))
08424     {
08425     /*
08426     * Try to find an equal ns-name in in-scope ns-decls.
08427     */
08428     XML_NSMAP_FOREACH(*nsMap, mi) {
08429         if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
08430         /*
08431         * ancestorsOnly: This should be turned on to gain speed,
08432         * if one knows that the branch itself was already
08433         * ns-wellformed and no stale references existed.
08434         * I.e. it searches in the ancestor axis only.
08435         */
08436         ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
08437         /* Skip shadowed prefixes. */
08438         (mi->shadowDepth == -1) &&
08439         /* Skip xmlns="" or xmlns:foo="". */
08440         ((mi->newNs->href != NULL) &&
08441         (mi->newNs->href[0] != 0)) &&
08442         /* Ensure a prefix if wanted. */
08443         ((! prefixed) || (mi->newNs->prefix != NULL)) &&
08444         /* Equal ns name */
08445         ((mi->newNs->href == ns->href) ||
08446         xmlStrEqual(mi->newNs->href, ns->href))) {
08447         /* Set the mapping. */
08448         mi->oldNs = ns;
08449         *retNs = mi->newNs;
08450         return (0);
08451         }
08452     }
08453     }
08454     /*
08455     * No luck, the namespace is out of scope or shadowed.
08456     */
08457     if (elem == NULL) {
08458     xmlNsPtr tmpns;
08459 
08460     /*
08461     * Store ns-decls in "oldNs" of the document-node.
08462     */
08463     tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
08464     if (tmpns == NULL)
08465         return (-1);
08466     /*
08467     * Insert mapping.
08468     */
08469     if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
08470         tmpns, XML_TREE_NSMAP_DOC) == NULL) {
08471         xmlFreeNs(tmpns);
08472         return (-1);
08473     }
08474     *retNs = tmpns;
08475     } else {
08476     xmlNsPtr tmpns;
08477 
08478     tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
08479         ns->prefix, 0);
08480     if (tmpns == NULL)
08481         return (-1);
08482 
08483     if (*nsMap != NULL) {
08484         /*
08485         * Does it shadow ancestor ns-decls?
08486         */
08487         XML_NSMAP_FOREACH(*nsMap, mi) {
08488         if ((mi->depth < depth) &&
08489             (mi->shadowDepth == -1) &&
08490             ((ns->prefix == mi->newNs->prefix) ||
08491             xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
08492             /*
08493             * Shadows.
08494             */
08495             mi->shadowDepth = depth;
08496             break;
08497         }
08498         }
08499     }
08500     if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
08501         xmlFreeNs(tmpns);
08502         return (-1);
08503     }
08504     *retNs = tmpns;
08505     }
08506     return (0);
08507 }
08508 
08509 typedef enum {
08510     XML_DOM_RECONNS_REMOVEREDUND = 1<<0
08511 } xmlDOMReconcileNSOptions;
08512 
08513 /*
08514 * xmlDOMWrapReconcileNamespaces:
08515 * @ctxt: DOM wrapper context, unused at the moment
08516 * @elem: the element-node
08517 * @options: option flags
08518 *
08519 * Ensures that ns-references point to ns-decls hold on element-nodes.
08520 * Ensures that the tree is namespace wellformed by creating additional
08521 * ns-decls where needed. Note that, since prefixes of already existent
08522 * ns-decls can be shadowed by this process, it could break QNames in
08523 * attribute values or element content.
08524 *
08525 * NOTE: This function was not intensively tested.
08526 *
08527 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
08528 */
08529 
08530 int
08531 xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
08532                   xmlNodePtr elem,
08533                   int options)
08534 {
08535     int depth = -1, adoptns = 0, parnsdone = 0;
08536     xmlNsPtr ns, prevns;
08537     xmlDocPtr doc;
08538     xmlNodePtr cur, curElem = NULL;
08539     xmlNsMapPtr nsMap = NULL;
08540     xmlNsMapItemPtr /* topmi = NULL, */ mi;
08541     /* @ancestorsOnly should be set by an option flag. */
08542     int ancestorsOnly = 0;
08543     int optRemoveRedundantNS =
08544     ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
08545     xmlNsPtr *listRedund = NULL;
08546     int sizeRedund = 0, nbRedund = 0, ret, i, j;
08547 
08548     if ((elem == NULL) || (elem->doc == NULL) ||
08549     (elem->type != XML_ELEMENT_NODE))
08550     return (-1);
08551 
08552     doc = elem->doc;
08553     cur = elem;
08554     do {
08555     switch (cur->type) {
08556         case XML_ELEMENT_NODE:
08557         adoptns = 1;
08558         curElem = cur;
08559         depth++;
08560         /*
08561         * Namespace declarations.
08562         */
08563         if (cur->nsDef != NULL) {
08564             prevns = NULL;
08565             ns = cur->nsDef;
08566             while (ns != NULL) {
08567             if (! parnsdone) {
08568                 if ((elem->parent) &&
08569                 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
08570                 /*
08571                 * Gather ancestor in-scope ns-decls.
08572                 */
08573                 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
08574                     elem->parent) == -1)
08575                     goto internal_error;
08576                 }
08577                 parnsdone = 1;
08578             }
08579 
08580             /*
08581             * Lookup the ns ancestor-axis for equal ns-decls in scope.
08582             */
08583             if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
08584                 XML_NSMAP_FOREACH(nsMap, mi) {
08585                 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
08586                     (mi->shadowDepth == -1) &&
08587                     ((ns->prefix == mi->newNs->prefix) ||
08588                       xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
08589                     ((ns->href == mi->newNs->href) ||
08590                       xmlStrEqual(ns->href, mi->newNs->href)))
08591                 {
08592                     /*
08593                     * A redundant ns-decl was found.
08594                     * Add it to the list of redundant ns-decls.
08595                     */
08596                     if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
08597                     &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
08598                     goto internal_error;
08599                     /*
08600                     * Remove the ns-decl from the element-node.
08601                     */
08602                     if (prevns)
08603                     prevns->next = ns->next;
08604                     else
08605                     cur->nsDef = ns->next;
08606                     goto next_ns_decl;
08607                 }
08608                 }
08609             }
08610 
08611             /*
08612             * Skip ns-references handling if the referenced
08613             * ns-decl is declared on the same element.
08614             */
08615             if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
08616                 adoptns = 0;
08617             /*
08618             * Does it shadow any ns-decl?
08619             */
08620             if (XML_NSMAP_NOTEMPTY(nsMap)) {
08621                 XML_NSMAP_FOREACH(nsMap, mi) {
08622                 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
08623                     (mi->shadowDepth == -1) &&
08624                     ((ns->prefix == mi->newNs->prefix) ||
08625                     xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
08626 
08627                     mi->shadowDepth = depth;
08628                 }
08629                 }
08630             }
08631             /*
08632             * Push mapping.
08633             */
08634             if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
08635                 depth) == NULL)
08636                 goto internal_error;
08637 
08638             prevns = ns;
08639 next_ns_decl:
08640             ns = ns->next;
08641             }
08642         }
08643         if (! adoptns)
08644             goto ns_end;
08645         /* No break on purpose. */
08646         case XML_ATTRIBUTE_NODE:
08647         /* No ns, no fun. */
08648         if (cur->ns == NULL)
08649             goto ns_end;
08650 
08651         if (! parnsdone) {
08652             if ((elem->parent) &&
08653             ((xmlNodePtr) elem->parent->doc != elem->parent)) {
08654             if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
08655                 elem->parent) == -1)
08656                 goto internal_error;
08657             }
08658             parnsdone = 1;
08659         }
08660         /*
08661         * Adjust the reference if this was a redundant ns-decl.
08662         */
08663         if (listRedund) {
08664            for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
08665                if (cur->ns == listRedund[j]) {
08666                cur->ns = listRedund[++j];
08667                break;
08668                }
08669            }
08670         }
08671         /*
08672         * Adopt ns-references.
08673         */
08674         if (XML_NSMAP_NOTEMPTY(nsMap)) {
08675             /*
08676             * Search for a mapping.
08677             */
08678             XML_NSMAP_FOREACH(nsMap, mi) {
08679             if ((mi->shadowDepth == -1) &&
08680                 (cur->ns == mi->oldNs)) {
08681 
08682                 cur->ns = mi->newNs;
08683                 goto ns_end;
08684             }
08685             }
08686         }
08687         /*
08688         * Aquire a normalized ns-decl and add it to the map.
08689         */
08690         if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
08691             cur->ns, &ns,
08692             &nsMap, depth,
08693             ancestorsOnly,
08694             (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
08695             goto internal_error;
08696         cur->ns = ns;
08697 
08698 ns_end:
08699         if ((cur->type == XML_ELEMENT_NODE) &&
08700             (cur->properties != NULL)) {
08701             /*
08702             * Process attributes.
08703             */
08704             cur = (xmlNodePtr) cur->properties;
08705             continue;
08706         }
08707         break;
08708         default:
08709         goto next_sibling;
08710     }
08711 into_content:
08712     if ((cur->type == XML_ELEMENT_NODE) &&
08713         (cur->children != NULL)) {
08714         /*
08715         * Process content of element-nodes only.
08716         */
08717         cur = cur->children;
08718         continue;
08719     }
08720 next_sibling:
08721     if (cur == elem)
08722         break;
08723     if (cur->type == XML_ELEMENT_NODE) {
08724         if (XML_NSMAP_NOTEMPTY(nsMap)) {
08725         /*
08726         * Pop mappings.
08727         */
08728         while ((nsMap->last != NULL) &&
08729             (nsMap->last->depth >= depth))
08730         {
08731             XML_NSMAP_POP(nsMap, mi)
08732         }
08733         /*
08734         * Unshadow.
08735         */
08736         XML_NSMAP_FOREACH(nsMap, mi) {
08737             if (mi->shadowDepth >= depth)
08738             mi->shadowDepth = -1;
08739         }
08740         }
08741         depth--;
08742     }
08743     if (cur->next != NULL)
08744         cur = cur->next;
08745     else {
08746         if (cur->type == XML_ATTRIBUTE_NODE) {
08747         cur = cur->parent;
08748         goto into_content;
08749         }
08750         cur = cur->parent;
08751         goto next_sibling;
08752     }
08753     } while (cur != NULL);
08754 
08755     ret = 0;
08756     goto exit;
08757 internal_error:
08758     ret = -1;
08759 exit:
08760     if (listRedund) {
08761     for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
08762         xmlFreeNs(listRedund[j]);
08763     }
08764     xmlFree(listRedund);
08765     }
08766     if (nsMap != NULL)
08767     xmlDOMWrapNsMapFree(nsMap);
08768     return (ret);
08769 }
08770 
08771 /*
08772 * xmlDOMWrapAdoptBranch:
08773 * @ctxt: the optional context for custom processing
08774 * @sourceDoc: the optional sourceDoc
08775 * @node: the element-node to start with
08776 * @destDoc: the destination doc for adoption
08777 * @destParent: the optional new parent of @node in @destDoc
08778 * @options: option flags
08779 *
08780 * Ensures that ns-references point to @destDoc: either to
08781 * elements->nsDef entries if @destParent is given, or to
08782 * @destDoc->oldNs otherwise.
08783 * If @destParent is given, it ensures that the tree is namespace
08784 * wellformed by creating additional ns-decls where needed.
08785 * Note that, since prefixes of already existent ns-decls can be
08786 * shadowed by this process, it could break QNames in attribute
08787 * values or element content.
08788 *
08789 * NOTE: This function was not intensively tested.
08790 *
08791 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
08792 */
08793 static int
08794 xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
08795               xmlDocPtr sourceDoc,
08796               xmlNodePtr node,
08797               xmlDocPtr destDoc,
08798               xmlNodePtr destParent,
08799               int options ATTRIBUTE_UNUSED)
08800 {
08801     int ret = 0;
08802     xmlNodePtr cur, curElem = NULL;
08803     xmlNsMapPtr nsMap = NULL;
08804     xmlNsMapItemPtr mi;
08805     xmlNsPtr ns = NULL;
08806     int depth = -1, adoptStr = 1;
08807     /* gather @parent's ns-decls. */
08808     int parnsdone;
08809     /* @ancestorsOnly should be set per option. */
08810     int ancestorsOnly = 0;
08811 
08812     /*
08813     * Optimize string adoption for equal or none dicts.
08814     */
08815     if ((sourceDoc != NULL) &&
08816     (sourceDoc->dict == destDoc->dict))
08817     adoptStr = 0;
08818     else
08819     adoptStr = 1;
08820 
08821     /*
08822     * Get the ns-map from the context if available.
08823     */
08824     if (ctxt)
08825     nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
08826     /*
08827     * Disable search for ns-decls in the parent-axis of the
08828     * desination element, if:
08829     * 1) there's no destination parent
08830     * 2) custom ns-reference handling is used
08831     */
08832     if ((destParent == NULL) ||
08833     (ctxt && ctxt->getNsForNodeFunc))
08834     {
08835     parnsdone = 1;
08836     } else
08837     parnsdone = 0;
08838 
08839     cur = node;
08840     while (cur != NULL) {
08841     /*
08842     * Paranoid source-doc sanity check.
08843     */
08844     if (cur->doc != sourceDoc) {
08845         /*
08846         * We'll assume XIncluded nodes if the doc differs.
08847         * TODO: Do we need to reconciliate XIncluded nodes?
08848         * This here skips XIncluded nodes and tries to handle
08849         * broken sequences.
08850         */
08851         if (cur->next == NULL)
08852         goto leave_node;
08853         do {
08854         cur = cur->next;
08855         if ((cur->type == XML_XINCLUDE_END) ||
08856             (cur->doc == node->doc))
08857             break;
08858         } while (cur->next != NULL);
08859 
08860         if (cur->doc != node->doc)
08861         goto leave_node;
08862     }
08863     cur->doc = destDoc;
08864     switch (cur->type) {
08865         case XML_XINCLUDE_START:
08866         case XML_XINCLUDE_END:
08867         /*
08868         * TODO
08869         */
08870         return (-1);
08871         case XML_ELEMENT_NODE:
08872         curElem = cur;
08873         depth++;
08874         /*
08875         * Namespace declarations.
08876         * - ns->href and ns->prefix are never in the dict, so
08877         *   we need not move the values over to the destination dict.
08878         * - Note that for custom handling of ns-references,
08879         *   the ns-decls need not be stored in the ns-map,
08880         *   since they won't be referenced by node->ns.
08881         */
08882         if ((cur->nsDef) &&
08883             ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL)))
08884         {
08885             if (! parnsdone) {
08886             /*
08887             * Gather @parent's in-scope ns-decls.
08888             */
08889             if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
08890                 destParent) == -1)
08891                 goto internal_error;
08892             parnsdone = 1;
08893             }
08894             for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
08895             /*
08896             * NOTE: ns->prefix and ns->href are never in the dict.
08897             * XML_TREE_ADOPT_STR(ns->prefix)
08898             * XML_TREE_ADOPT_STR(ns->href)
08899             */
08900             /*
08901             * Does it shadow any ns-decl?
08902             */
08903             if (XML_NSMAP_NOTEMPTY(nsMap)) {
08904                 XML_NSMAP_FOREACH(nsMap, mi) {
08905                 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
08906                     (mi->shadowDepth == -1) &&
08907                     ((ns->prefix == mi->newNs->prefix) ||
08908                     xmlStrEqual(ns->prefix,
08909                     mi->newNs->prefix))) {
08910 
08911                     mi->shadowDepth = depth;
08912                 }
08913                 }
08914             }
08915             /*
08916             * Push mapping.
08917             */
08918             if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
08919                 ns, ns, depth) == NULL)
08920                 goto internal_error;
08921             }
08922         }
08923         /* No break on purpose. */
08924         case XML_ATTRIBUTE_NODE:
08925         /* No namespace, no fun. */
08926         if (cur->ns == NULL)
08927             goto ns_end;
08928 
08929         if (! parnsdone) {
08930             if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
08931             destParent) == -1)
08932             goto internal_error;
08933             parnsdone = 1;
08934         }
08935         /*
08936         * Adopt ns-references.
08937         */
08938         if (XML_NSMAP_NOTEMPTY(nsMap)) {
08939             /*
08940             * Search for a mapping.
08941             */
08942             XML_NSMAP_FOREACH(nsMap, mi) {
08943             if ((mi->shadowDepth == -1) &&
08944                 (cur->ns == mi->oldNs)) {
08945 
08946                 cur->ns = mi->newNs;
08947                 goto ns_end;
08948             }
08949             }
08950         }
08951         /*
08952         * No matching namespace in scope. We need a new one.
08953         */
08954         if ((ctxt) && (ctxt->getNsForNodeFunc)) {
08955             /*
08956             * User-defined behaviour.
08957             */
08958             ns = ctxt->getNsForNodeFunc(ctxt, cur,
08959             cur->ns->href, cur->ns->prefix);
08960             /*
08961             * Insert mapping if ns is available; it's the users fault
08962             * if not.
08963             */
08964             if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
08965                 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
08966             goto internal_error;
08967             cur->ns = ns;
08968         } else {
08969             /*
08970             * Aquire a normalized ns-decl and add it to the map.
08971             */
08972             if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
08973             /* ns-decls on curElem or on destDoc->oldNs */
08974             destParent ? curElem : NULL,
08975             cur->ns, &ns,
08976             &nsMap, depth,
08977             ancestorsOnly,
08978             /* ns-decls must be prefixed for attributes. */
08979             (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
08980             goto internal_error;
08981             cur->ns = ns;
08982         }
08983 ns_end:
08984         /*
08985         * Further node properties.
08986         * TODO: Is this all?
08987         */
08988         XML_TREE_ADOPT_STR(cur->name)
08989         if (cur->type == XML_ELEMENT_NODE) {
08990             cur->psvi = NULL;
08991             cur->line = 0;
08992             cur->extra = 0;
08993             /*
08994             * Walk attributes.
08995             */
08996             if (cur->properties != NULL) {
08997             /*
08998             * Process first attribute node.
08999             */
09000             cur = (xmlNodePtr) cur->properties;
09001             continue;
09002             }
09003         } else {
09004             /*
09005             * Attributes.
09006             */
09007             if ((sourceDoc != NULL) &&
09008             (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
09009             {
09010             xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
09011             }
09012             ((xmlAttrPtr) cur)->atype = 0;
09013             ((xmlAttrPtr) cur)->psvi = NULL;
09014         }
09015         break;
09016         case XML_TEXT_NODE:
09017         case XML_CDATA_SECTION_NODE:
09018         /*
09019         * This puts the content in the dest dict, only if
09020         * it was previously in the source dict.
09021         */
09022         XML_TREE_ADOPT_STR_2(cur->content)
09023         goto leave_node;
09024         case XML_ENTITY_REF_NODE:
09025         /*
09026         * Remove reference to the entitity-node.
09027         */
09028         cur->content = NULL;
09029         cur->children = NULL;
09030         cur->last = NULL;
09031         if ((destDoc->intSubset) || (destDoc->extSubset)) {
09032             xmlEntityPtr ent;
09033             /*
09034             * Assign new entity-node if available.
09035             */
09036             ent = xmlGetDocEntity(destDoc, cur->name);
09037             if (ent != NULL) {
09038             cur->content = ent->content;
09039             cur->children = (xmlNodePtr) ent;
09040             cur->last = (xmlNodePtr) ent;
09041             }
09042         }
09043         goto leave_node;
09044         case XML_PI_NODE:
09045         XML_TREE_ADOPT_STR(cur->name)
09046         XML_TREE_ADOPT_STR_2(cur->content)
09047         break;
09048         case XML_COMMENT_NODE:
09049         break;
09050         default:
09051         goto internal_error;
09052     }
09053     /*
09054     * Walk the tree.
09055     */
09056     if (cur->children != NULL) {
09057         cur = cur->children;
09058         continue;
09059     }
09060 
09061 leave_node:
09062     if (cur == node)
09063         break;
09064     if ((cur->type == XML_ELEMENT_NODE) ||
09065         (cur->type == XML_XINCLUDE_START) ||
09066         (cur->type == XML_XINCLUDE_END))
09067     {
09068         /*
09069         * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
09070         */
09071         if (XML_NSMAP_NOTEMPTY(nsMap)) {
09072         /*
09073         * Pop mappings.
09074         */
09075         while ((nsMap->last != NULL) &&
09076             (nsMap->last->depth >= depth))
09077         {
09078             XML_NSMAP_POP(nsMap, mi)
09079         }
09080         /*
09081         * Unshadow.
09082         */
09083         XML_NSMAP_FOREACH(nsMap, mi) {
09084             if (mi->shadowDepth >= depth)
09085             mi->shadowDepth = -1;
09086         }
09087         }
09088         depth--;
09089     }
09090     if (cur->next != NULL)
09091         cur = cur->next;
09092     else if ((cur->type == XML_ATTRIBUTE_NODE) &&
09093         (cur->parent->children != NULL))
09094     {
09095         cur = cur->parent->children;
09096     } else {
09097         cur = cur->parent;
09098         goto leave_node;
09099     }
09100     }
09101 
09102     goto exit;
09103 
09104 internal_error:
09105     ret = -1;
09106 
09107 exit:
09108     /*
09109     * Cleanup.
09110     */
09111     if (nsMap != NULL) {
09112     if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
09113         /*
09114         * Just cleanup the map but don't free.
09115         */
09116         if (nsMap->first) {
09117         if (nsMap->pool)
09118             nsMap->last->next = nsMap->pool;
09119         nsMap->pool = nsMap->first;
09120         nsMap->first = NULL;
09121         }
09122     } else
09123         xmlDOMWrapNsMapFree(nsMap);
09124     }
09125     return(ret);
09126 }
09127 
09128 /*
09129 * xmlDOMWrapCloneNode:
09130 * @ctxt: the optional context for custom processing
09131 * @sourceDoc: the optional sourceDoc
09132 * @node: the node to start with
09133 * @resNode: the clone of the given @node
09134 * @destDoc: the destination doc
09135 * @destParent: the optional new parent of @node in @destDoc
09136 * @deep: descend into child if set
09137 * @options: option flags
09138 *
09139 * References of out-of scope ns-decls are remapped to point to @destDoc:
09140 * 1) If @destParent is given, then nsDef entries on element-nodes are used
09141 * 2) If *no* @destParent is given, then @destDoc->oldNs entries are used.
09142 *    This is the case when you don't know already where the cloned branch
09143 *    will be added to.
09144 *
09145 * If @destParent is given, it ensures that the tree is namespace
09146 * wellformed by creating additional ns-decls where needed.
09147 * Note that, since prefixes of already existent ns-decls can be
09148 * shadowed by this process, it could break QNames in attribute
09149 * values or element content.
09150 * TODO:
09151 *   1) What to do with XInclude? Currently this returns an error for XInclude.
09152 *
09153 * Returns 0 if the operation succeeded,
09154 *         1 if a node of unsupported (or not yet supported) type was given,
09155 *         -1 on API/internal errors.
09156 */
09157 
09158 int
09159 xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
09160               xmlDocPtr sourceDoc,
09161               xmlNodePtr node,
09162               xmlNodePtr *resNode,
09163               xmlDocPtr destDoc,
09164               xmlNodePtr destParent,
09165               int deep,
09166               int options ATTRIBUTE_UNUSED)
09167 {
09168     int ret = 0;
09169     xmlNodePtr cur, curElem = NULL;
09170     xmlNsMapPtr nsMap = NULL;
09171     xmlNsMapItemPtr mi;
09172     xmlNsPtr ns;
09173     int depth = -1;
09174     /* int adoptStr = 1; */
09175     /* gather @parent's ns-decls. */
09176     int parnsdone = 0;
09177     /*
09178     * @ancestorsOnly:
09179     * TODO: @ancestorsOnly should be set per option.
09180     *
09181     */
09182     int ancestorsOnly = 0;
09183     xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
09184     xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
09185     xmlDictPtr dict; /* The destination dict */
09186 
09187     if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
09188     return(-1);
09189     /*
09190     * TODO: Initially we support only element-nodes.
09191     */
09192     if (node->type != XML_ELEMENT_NODE)
09193     return(1);
09194     /*
09195     * Check node->doc sanity.
09196     */
09197     if ((node->doc != NULL) && (sourceDoc != NULL) &&
09198     (node->doc != sourceDoc)) {
09199     /*
09200     * Might be an XIncluded node.
09201     */
09202     return (-1);
09203     }
09204     if (sourceDoc == NULL)
09205     sourceDoc = node->doc;
09206     if (sourceDoc == NULL)
09207         return (-1);
09208 
09209     dict = destDoc->dict;
09210     /*
09211     * Reuse the namespace map of the context.
09212     */
09213     if (ctxt)
09214     nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
09215 
09216     *resNode = NULL;
09217 
09218     cur = node;
09219     while (cur != NULL) {
09220     if (cur->doc != sourceDoc) {
09221         /*
09222         * We'll assume XIncluded nodes if the doc differs.
09223         * TODO: Do we need to reconciliate XIncluded nodes?
09224         * TODO: This here returns -1 in this case.
09225         */
09226         goto internal_error;
09227     }
09228     /*
09229     * Create a new node.
09230     */
09231     switch (cur->type) {
09232         case XML_XINCLUDE_START:
09233         case XML_XINCLUDE_END:
09234         /*
09235         * TODO: What to do with XInclude?
09236         */
09237         goto internal_error;
09238         break;
09239         case XML_ELEMENT_NODE:
09240         case XML_TEXT_NODE:
09241         case XML_CDATA_SECTION_NODE:
09242         case XML_COMMENT_NODE:
09243         case XML_PI_NODE:
09244         case XML_DOCUMENT_FRAG_NODE:
09245         case XML_ENTITY_REF_NODE:
09246         case XML_ENTITY_NODE:
09247         /*
09248         * Nodes of xmlNode structure.
09249         */
09250         clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
09251         if (clone == NULL) {
09252             xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node");
09253             goto internal_error;
09254         }
09255         memset(clone, 0, sizeof(xmlNode));
09256         /*
09257         * Set hierachical links.
09258         */
09259         if (resultClone != NULL) {
09260             clone->parent = parentClone;
09261             if (prevClone) {
09262             prevClone->next = clone;
09263             clone->prev = prevClone;
09264             } else
09265             parentClone->children = clone;
09266         } else
09267             resultClone = clone;
09268 
09269         break;
09270         case XML_ATTRIBUTE_NODE:
09271         /*
09272         * Attributes (xmlAttr).
09273         */
09274         clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
09275         if (clone == NULL) {
09276             xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node");
09277             goto internal_error;
09278         }
09279         memset(clone, 0, sizeof(xmlAttr));
09280         /*
09281         * Set hierachical links.
09282         * TODO: Change this to add to the end of attributes.
09283         */
09284         if (resultClone != NULL) {
09285             clone->parent = parentClone;
09286             if (prevClone) {
09287             prevClone->next = clone;
09288             clone->prev = prevClone;
09289             } else
09290             parentClone->properties = (xmlAttrPtr) clone;
09291         } else
09292             resultClone = clone;
09293         break;
09294         default:
09295         /*
09296         * TODO QUESTION: Any other nodes expected?
09297         */
09298         goto internal_error;
09299     }
09300 
09301     clone->type = cur->type;
09302     clone->doc = destDoc;
09303 
09304     /*
09305     * Clone the name of the node if any.
09306     */
09307     if (cur->name == xmlStringText)
09308         clone->name = xmlStringText;
09309     else if (cur->name == xmlStringTextNoenc)
09310         /*
09311         * NOTE: Although xmlStringTextNoenc is never assigned to a node
09312         *   in tree.c, it might be set in Libxslt via
09313         *   "xsl:disable-output-escaping".
09314         */
09315         clone->name = xmlStringTextNoenc;
09316     else if (cur->name == xmlStringComment)
09317         clone->name = xmlStringComment;
09318     else if (cur->name != NULL) {
09319         DICT_CONST_COPY(cur->name, clone->name);
09320     }
09321 
09322     switch (cur->type) {
09323         case XML_XINCLUDE_START:
09324         case XML_XINCLUDE_END:
09325         /*
09326         * TODO
09327         */
09328         return (-1);
09329         case XML_ELEMENT_NODE:
09330         curElem = cur;
09331         depth++;
09332         /*
09333         * Namespace declarations.
09334         */
09335         if (cur->nsDef != NULL) {
09336             if (! parnsdone) {
09337             if (destParent && (ctxt == NULL)) {
09338                 /*
09339                 * Gather @parent's in-scope ns-decls.
09340                 */
09341                 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
09342                 destParent) == -1)
09343                 goto internal_error;
09344             }
09345             parnsdone = 1;
09346             }
09347             /*
09348             * Clone namespace declarations.
09349             */
09350             cloneNsDefSlot = &(clone->nsDef);
09351             for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
09352             /*
09353             * Create a new xmlNs.
09354             */
09355             cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
09356             if (cloneNs == NULL) {
09357                 xmlTreeErrMemory("xmlDOMWrapCloneNode(): "
09358                 "allocating namespace");
09359                 return(-1);
09360             }
09361             memset(cloneNs, 0, sizeof(xmlNs));
09362             cloneNs->type = XML_LOCAL_NAMESPACE;
09363 
09364             if (ns->href != NULL)
09365                 cloneNs->href = xmlStrdup(ns->href);
09366             if (ns->prefix != NULL)
09367                 cloneNs->prefix = xmlStrdup(ns->prefix);
09368 
09369             *cloneNsDefSlot = cloneNs;
09370             cloneNsDefSlot = &(cloneNs->next);
09371 
09372             /*
09373             * Note that for custom handling of ns-references,
09374             * the ns-decls need not be stored in the ns-map,
09375             * since they won't be referenced by node->ns.
09376             */
09377             if ((ctxt == NULL) ||
09378                 (ctxt->getNsForNodeFunc == NULL))
09379             {
09380                 /*
09381                 * Does it shadow any ns-decl?
09382                 */
09383                 if (XML_NSMAP_NOTEMPTY(nsMap)) {
09384                 XML_NSMAP_FOREACH(nsMap, mi) {
09385                     if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
09386                     (mi->shadowDepth == -1) &&
09387                     ((ns->prefix == mi->newNs->prefix) ||
09388                     xmlStrEqual(ns->prefix,
09389                     mi->newNs->prefix))) {
09390                     /*
09391                     * Mark as shadowed at the current
09392                     * depth.
09393                     */
09394                     mi->shadowDepth = depth;
09395                     }
09396                 }
09397                 }
09398                 /*
09399                 * Push mapping.
09400                 */
09401                 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
09402                 ns, cloneNs, depth) == NULL)
09403                 goto internal_error;
09404             }
09405             }
09406         }
09407         /* cur->ns will be processed further down. */
09408         break;
09409         case XML_ATTRIBUTE_NODE:
09410         /* IDs will be processed further down. */
09411         /* cur->ns will be processed further down. */
09412         break;
09413         case XML_TEXT_NODE:
09414         case XML_CDATA_SECTION_NODE:
09415         /*
09416         * Note that this will also cover the values of attributes.
09417         */
09418         DICT_COPY(cur->content, clone->content);
09419         goto leave_node;
09420         case XML_ENTITY_NODE:
09421         /* TODO: What to do here? */
09422         goto leave_node;
09423         case XML_ENTITY_REF_NODE:
09424         if (sourceDoc != destDoc) {
09425             if ((destDoc->intSubset) || (destDoc->extSubset)) {
09426             xmlEntityPtr ent;
09427             /*
09428             * Different doc: Assign new entity-node if available.
09429             */
09430             ent = xmlGetDocEntity(destDoc, cur->name);
09431             if (ent != NULL) {
09432                 clone->content = ent->content;
09433                 clone->children = (xmlNodePtr) ent;
09434                 clone->last = (xmlNodePtr) ent;
09435             }
09436             }
09437         } else {
09438             /*
09439             * Same doc: Use the current node's entity declaration
09440             * and value.
09441             */
09442             clone->content = cur->content;
09443             clone->children = cur->children;
09444             clone->last = cur->last;
09445         }
09446         goto leave_node;
09447         case XML_PI_NODE:
09448         DICT_COPY(cur->content, clone->content);
09449         goto leave_node;
09450         case XML_COMMENT_NODE:
09451         DICT_COPY(cur->content, clone->content);
09452         goto leave_node;
09453         default:
09454         goto internal_error;
09455     }
09456 
09457     if (cur->ns == NULL)
09458         goto end_ns_reference;
09459 
09460 /* handle_ns_reference: */
09461     /*
09462     ** The following will take care of references to ns-decls ********
09463     ** and is intended only for element- and attribute-nodes.
09464     **
09465     */
09466     if (! parnsdone) {
09467         if (destParent && (ctxt == NULL)) {
09468         if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
09469             goto internal_error;
09470         }
09471         parnsdone = 1;
09472     }
09473     /*
09474     * Adopt ns-references.
09475     */
09476     if (XML_NSMAP_NOTEMPTY(nsMap)) {
09477         /*
09478         * Search for a mapping.
09479         */
09480         XML_NSMAP_FOREACH(nsMap, mi) {
09481         if ((mi->shadowDepth == -1) &&
09482             (cur->ns == mi->oldNs)) {
09483             /*
09484             * This is the nice case: a mapping was found.
09485             */
09486             clone->ns = mi->newNs;
09487             goto end_ns_reference;
09488         }
09489         }
09490     }
09491     /*
09492     * No matching namespace in scope. We need a new one.
09493     */
09494     if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) {
09495         /*
09496         * User-defined behaviour.
09497         */
09498         ns = ctxt->getNsForNodeFunc(ctxt, cur,
09499         cur->ns->href, cur->ns->prefix);
09500         /*
09501         * Add user's mapping.
09502         */
09503         if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
09504         cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
09505         goto internal_error;
09506         clone->ns = ns;
09507     } else {
09508         /*
09509         * Aquire a normalized ns-decl and add it to the map.
09510         */
09511         if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
09512         /* ns-decls on curElem or on destDoc->oldNs */
09513         destParent ? curElem : NULL,
09514         cur->ns, &ns,
09515         &nsMap, depth,
09516         /* if we need to search only in the ancestor-axis */
09517         ancestorsOnly,
09518         /* ns-decls must be prefixed for attributes. */
09519         (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
09520         goto internal_error;
09521         clone->ns = ns;
09522     }
09523 
09524 end_ns_reference:
09525 
09526     /*
09527     * Some post-processing.
09528     *
09529     * Handle ID attributes.
09530     */
09531     if ((clone->type == XML_ATTRIBUTE_NODE) &&
09532         (clone->parent != NULL))
09533     {
09534         if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
09535 
09536         xmlChar *idVal;
09537 
09538         idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
09539         if (idVal != NULL) {
09540             if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
09541             /* TODO: error message. */
09542             xmlFree(idVal);
09543             goto internal_error;
09544             }
09545             xmlFree(idVal);
09546         }
09547         }
09548     }
09549     /*
09550     **
09551     ** The following will traverse the tree **************************
09552     **
09553     *
09554     * Walk the element's attributes before descending into child-nodes.
09555     */
09556     if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
09557         prevClone = NULL;
09558         parentClone = clone;
09559         cur = (xmlNodePtr) cur->properties;
09560         continue;
09561     }
09562 into_content:
09563     /*
09564     * Descend into child-nodes.
09565     */
09566     if (cur->children != NULL) {
09567         if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
09568         prevClone = NULL;
09569         parentClone = clone;
09570         cur = cur->children;
09571         continue;
09572         }
09573     }
09574 
09575 leave_node:
09576     /*
09577     * At this point we are done with the node, its content
09578     * and an element-nodes's attribute-nodes.
09579     */
09580     if (cur == node)
09581         break;
09582     if ((cur->type == XML_ELEMENT_NODE) ||
09583         (cur->type == XML_XINCLUDE_START) ||
09584         (cur->type == XML_XINCLUDE_END)) {
09585         /*
09586         * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
09587         */
09588         if (XML_NSMAP_NOTEMPTY(nsMap)) {
09589         /*
09590         * Pop mappings.
09591         */
09592         while ((nsMap->last != NULL) &&
09593             (nsMap->last->depth >= depth))
09594         {
09595             XML_NSMAP_POP(nsMap, mi)
09596         }
09597         /*
09598         * Unshadow.
09599         */
09600         XML_NSMAP_FOREACH(nsMap, mi) {
09601             if (mi->shadowDepth >= depth)
09602             mi->shadowDepth = -1;
09603         }
09604         }
09605         depth--;
09606     }
09607     if (cur->next != NULL) {
09608         prevClone = clone;
09609         cur = cur->next;
09610     } else if (cur->type != XML_ATTRIBUTE_NODE) {
09611         /*
09612         * Set clone->last.
09613         */
09614         if (clone->parent != NULL)
09615         clone->parent->last = clone;
09616         clone = clone->parent;
09617         parentClone = clone->parent;
09618         /*
09619         * Process parent --> next;
09620         */
09621         cur = cur->parent;
09622         goto leave_node;
09623     } else {
09624         /* This is for attributes only. */
09625         clone = clone->parent;
09626         parentClone = clone->parent;
09627         /*
09628         * Process parent-element --> children.
09629         */
09630         cur = cur->parent;
09631         goto into_content;
09632     }
09633     }
09634     goto exit;
09635 
09636 internal_error:
09637     ret = -1;
09638 
09639 exit:
09640     /*
09641     * Cleanup.
09642     */
09643     if (nsMap != NULL) {
09644     if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
09645         /*
09646         * Just cleanup the map but don't free.
09647         */
09648         if (nsMap->first) {
09649         if (nsMap->pool)
09650             nsMap->last->next = nsMap->pool;
09651         nsMap->pool = nsMap->first;
09652         nsMap->first = NULL;
09653         }
09654     } else
09655         xmlDOMWrapNsMapFree(nsMap);
09656     }
09657     /*
09658     * TODO: Should we try a cleanup of the cloned node in case of a
09659     * fatal error?
09660     */
09661     *resNode = resultClone;
09662     return (ret);
09663 }
09664 
09665 /*
09666 * xmlDOMWrapAdoptAttr:
09667 * @ctxt: the optional context for custom processing
09668 * @sourceDoc: the optional source document of attr
09669 * @attr: the attribute-node to be adopted
09670 * @destDoc: the destination doc for adoption
09671 * @destParent: the optional new parent of @attr in @destDoc
09672 * @options: option flags
09673 *
09674 * @attr is adopted by @destDoc.
09675 * Ensures that ns-references point to @destDoc: either to
09676 * elements->nsDef entries if @destParent is given, or to
09677 * @destDoc->oldNs otherwise.
09678 *
09679 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
09680 */
09681 static int
09682 xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
09683             xmlDocPtr sourceDoc,
09684             xmlAttrPtr attr,
09685             xmlDocPtr destDoc,
09686             xmlNodePtr destParent,
09687             int options ATTRIBUTE_UNUSED)
09688 {
09689     xmlNodePtr cur;
09690     int adoptStr = 1;
09691 
09692     if ((attr == NULL) || (destDoc == NULL))
09693     return (-1);
09694 
09695     attr->doc = destDoc;
09696     if (attr->ns != NULL) {
09697     xmlNsPtr ns = NULL;
09698 
09699     if (ctxt != NULL) {
09700         /* TODO: User defined. */
09701     }
09702     /* XML Namespace. */
09703     if (IS_STR_XML(attr->ns->prefix)) {
09704         ns = xmlTreeEnsureXMLDecl(destDoc);
09705     } else if (destParent == NULL) {
09706         /*
09707         * Store in @destDoc->oldNs.
09708         */
09709         ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
09710     } else {
09711         /*
09712         * Declare on @destParent.
09713         */
09714         if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
09715         &ns, 1) == -1)
09716         goto internal_error;
09717         if (ns == NULL) {
09718         ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
09719             attr->ns->href, attr->ns->prefix, 1);
09720         }
09721     }
09722     if (ns == NULL)
09723         goto internal_error;
09724     attr->ns = ns;
09725     }
09726 
09727     XML_TREE_ADOPT_STR(attr->name);
09728     attr->atype = 0;
09729     attr->psvi = NULL;
09730     /*
09731     * Walk content.
09732     */
09733     if (attr->children == NULL)
09734     return (0);
09735     cur = attr->children;
09736     while (cur != NULL) {
09737     cur->doc = destDoc;
09738     switch (cur->type) {
09739         case XML_TEXT_NODE:
09740         case XML_CDATA_SECTION_NODE:
09741         XML_TREE_ADOPT_STR_2(cur->content)
09742         break;
09743         case XML_ENTITY_REF_NODE:
09744         /*
09745         * Remove reference to the entitity-node.
09746         */
09747         cur->content = NULL;
09748         cur->children = NULL;
09749         cur->last = NULL;
09750         if ((destDoc->intSubset) || (destDoc->extSubset)) {
09751             xmlEntityPtr ent;
09752             /*
09753             * Assign new entity-node if available.
09754             */
09755             ent = xmlGetDocEntity(destDoc, cur->name);
09756             if (ent != NULL) {
09757             cur->content = ent->content;
09758             cur->children = (xmlNodePtr) ent;
09759             cur->last = (xmlNodePtr) ent;
09760             }
09761         }
09762         break;
09763         default:
09764         break;
09765     }
09766     if (cur->children != NULL) {
09767         cur = cur->children;
09768         continue;
09769     }
09770 next_sibling:
09771     if (cur == (xmlNodePtr) attr)
09772         break;
09773     if (cur->next != NULL)
09774         cur = cur->next;
09775     else {
09776         cur = cur->parent;
09777         goto next_sibling;
09778     }
09779     }
09780     return (0);
09781 internal_error:
09782     return (-1);
09783 }
09784 
09785 /*
09786 * xmlDOMWrapAdoptNode:
09787 * @ctxt: the optional context for custom processing
09788 * @sourceDoc: the optional sourceDoc
09789 * @node: the node to start with
09790 * @destDoc: the destination doc
09791 * @destParent: the optional new parent of @node in @destDoc
09792 * @options: option flags
09793 *
09794 * References of out-of scope ns-decls are remapped to point to @destDoc:
09795 * 1) If @destParent is given, then nsDef entries on element-nodes are used
09796 * 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
09797 *    This is the case when you have an unliked node and just want to move it
09798 *    to the context of
09799 *
09800 * If @destParent is given, it ensures that the tree is namespace
09801 * wellformed by creating additional ns-decls where needed.
09802 * Note that, since prefixes of already existent ns-decls can be
09803 * shadowed by this process, it could break QNames in attribute
09804 * values or element content.
09805 * NOTE: This function was not intensively tested.
09806 *
09807 * Returns 0 if the operation succeeded,
09808 *         1 if a node of unsupported type was given,
09809 *         2 if a node of not yet supported type was given and
09810 *         -1 on API/internal errors.
09811 */
09812 int
09813 xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
09814             xmlDocPtr sourceDoc,
09815             xmlNodePtr node,
09816             xmlDocPtr destDoc,
09817             xmlNodePtr destParent,
09818             int options)
09819 {
09820     if ((node == NULL) || (destDoc == NULL) ||
09821     ((destParent != NULL) && (destParent->doc != destDoc)))
09822     return(-1);
09823     /*
09824     * Check node->doc sanity.
09825     */
09826     if ((node->doc != NULL) && (sourceDoc != NULL) &&
09827     (node->doc != sourceDoc)) {
09828     /*
09829     * Might be an XIncluded node.
09830     */
09831     return (-1);
09832     }
09833     if (sourceDoc == NULL)
09834     sourceDoc = node->doc;
09835     if (sourceDoc == destDoc)
09836     return (-1);
09837     switch (node->type) {
09838     case XML_ELEMENT_NODE:
09839     case XML_ATTRIBUTE_NODE:
09840     case XML_TEXT_NODE:
09841     case XML_CDATA_SECTION_NODE:
09842     case XML_ENTITY_REF_NODE:
09843     case XML_PI_NODE:
09844     case XML_COMMENT_NODE:
09845         break;
09846     case XML_DOCUMENT_FRAG_NODE:
09847         /* TODO: Support document-fragment-nodes. */
09848         return (2);
09849     default:
09850         return (1);
09851     }
09852     /*
09853     * Unlink only if @node was not already added to @destParent.
09854     */
09855     if ((node->parent != NULL) && (destParent != node->parent))
09856     xmlUnlinkNode(node);
09857 
09858     if (node->type == XML_ELEMENT_NODE) {
09859         return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
09860             destDoc, destParent, options));
09861     } else if (node->type == XML_ATTRIBUTE_NODE) {
09862         return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
09863         (xmlAttrPtr) node, destDoc, destParent, options));
09864     } else {
09865     xmlNodePtr cur = node;
09866     int adoptStr = 1;
09867 
09868     cur->doc = destDoc;
09869     /*
09870     * Optimize string adoption.
09871     */
09872     if ((sourceDoc != NULL) &&
09873         (sourceDoc->dict == destDoc->dict))
09874         adoptStr = 0;
09875     switch (node->type) {
09876         case XML_TEXT_NODE:
09877         case XML_CDATA_SECTION_NODE:
09878         XML_TREE_ADOPT_STR_2(node->content)
09879             break;
09880         case XML_ENTITY_REF_NODE:
09881         /*
09882         * Remove reference to the entitity-node.
09883         */
09884         node->content = NULL;
09885         node->children = NULL;
09886         node->last = NULL;
09887         if ((destDoc->intSubset) || (destDoc->extSubset)) {
09888             xmlEntityPtr ent;
09889             /*
09890             * Assign new entity-node if available.
09891             */
09892             ent = xmlGetDocEntity(destDoc, node->name);
09893             if (ent != NULL) {
09894             node->content = ent->content;
09895             node->children = (xmlNodePtr) ent;
09896             node->last = (xmlNodePtr) ent;
09897             }
09898         }
09899         XML_TREE_ADOPT_STR(node->name)
09900         break;
09901         case XML_PI_NODE: {
09902         XML_TREE_ADOPT_STR(node->name)
09903         XML_TREE_ADOPT_STR_2(node->content)
09904         break;
09905         }
09906         default:
09907         break;
09908     }
09909     }
09910     return (0);
09911 }
09912 
09913 #define bottom_tree
09914 #include "elfgcchack.h"

Generated on Sat May 26 2012 04:22:05 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.