tree.c
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:112k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

  1. /*
  2.  * tree.c : implemetation of access function for an XML tree.
  3.  *
  4.  * See Copyright for the status of this software.
  5.  *
  6.  * Daniel.Veillard@w3.org
  7.  */
  8. #ifdef WIN32
  9. #include "win32config.h"
  10. #else
  11. #include "config.h"
  12. #endif
  13. #include <stdio.h>
  14. #include <string.h> /* for memset() only ! */
  15. #ifdef HAVE_CTYPE_H
  16. #include <ctype.h>
  17. #endif
  18. #ifdef HAVE_STDLIB_H
  19. #include <stdlib.h>
  20. #endif
  21. #ifdef HAVE_ZLIB_H
  22. #include <zlib.h>
  23. #endif
  24. #include <libxml/xmlmemory.h>
  25. #include <libxml/tree.h>
  26. #include <libxml/parser.h>
  27. #include <libxml/entities.h>
  28. #include <libxml/valid.h>
  29. static xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
  30. static xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
  31. int oldXMLWDcompatibility = 0;
  32. int xmlIndentTreeOutput = 0;
  33. xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT;
  34. static int xmlCompressMode = 0;
  35. static int xmlCheckDTD = 1;
  36. int xmlSaveNoEmptyTags = 0;
  37. #define IS_BLANK(c)
  38.   (((c) == 'n') || ((c) == 'r') || ((c) == 't') || ((c) == ' '))
  39. #define UPDATE_LAST_CHILD(n) if ((n) != NULL) {
  40.     xmlNodePtr ulccur = (n)->children;
  41.     if (ulccur == NULL) {
  42.         (n)->last = NULL;
  43.     } else {
  44.         while (ulccur->next != NULL) ulccur = ulccur->next;
  45. (n)->last = ulccur;
  46. }}
  47. /* #define DEBUG_BUFFER */
  48. /* #define DEBUG_TREE */
  49. /************************************************************************
  50.  * *
  51.  * Allocation and deallocation of basic structures *
  52.  * *
  53.  ************************************************************************/
  54.  
  55. /**
  56.  * xmlSetBufferAllocationScheme:
  57.  * @scheme:  allocation method to use
  58.  * 
  59.  * Set the buffer allocation method.  Types are
  60.  * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
  61.  * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed, 
  62.  *                             improves performance
  63.  */
  64. void
  65. xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
  66.     xmlBufferAllocScheme = scheme;
  67. }
  68. /**
  69.  * xmlGetBufferAllocationScheme:
  70.  *
  71.  * Types are
  72.  * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
  73.  * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed, 
  74.  *                             improves performance
  75.  * 
  76.  * Returns the current allocation scheme
  77.  */
  78. xmlBufferAllocationScheme
  79. xmlGetBufferAllocationScheme() {
  80.     return xmlBufferAllocScheme;
  81. }
  82. /**
  83.  * xmlUpgradeOldNs:
  84.  * @doc:  a document pointer
  85.  * 
  86.  * Upgrade old style Namespaces (PI) and move them to the root of the document.
  87.  */
  88. void
  89. xmlUpgradeOldNs(xmlDocPtr doc) {
  90.     xmlNsPtr cur;
  91.     if ((doc == NULL) || (doc->oldNs == NULL)) return;
  92.     if (doc->children == NULL) {
  93. #ifdef DEBUG_TREE
  94.         fprintf(stderr, "xmlUpgradeOldNs: failed no root !n");
  95. #endif
  96. return;
  97.     }
  98.     cur = doc->oldNs;
  99.     while (cur->next != NULL) {
  100. cur->type = XML_LOCAL_NAMESPACE;
  101.         cur = cur->next;
  102.     }
  103.     cur->type = XML_LOCAL_NAMESPACE;
  104.     cur->next = doc->children->nsDef;
  105.     doc->children->nsDef = doc->oldNs;
  106.     doc->oldNs = NULL;
  107. }
  108. /**
  109.  * xmlNewNs:
  110.  * @node:  the element carrying the namespace
  111.  * @href:  the URI associated
  112.  * @prefix:  the prefix for the namespace
  113.  *
  114.  * Creation of a new Namespace. This function will refuse to create
  115.  * a namespace with a similar prefix than an existing one present on this
  116.  * node.
  117.  * Returns returns a new namespace pointer or NULL
  118.  */
  119. xmlNsPtr
  120. xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
  121.     xmlNsPtr cur;
  122.     if (href == NULL) {
  123. #ifdef DEBUG_TREE
  124.         fprintf(stderr, "xmlNewNs: href == NULL !n");
  125. #endif
  126. return(NULL);
  127.     }
  128.     /*
  129.      * Allocate a new Namespace and fill the fields.
  130.      */
  131.     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
  132.     if (cur == NULL) {
  133.         fprintf(stderr, "xmlNewNs : malloc failedn");
  134. return(NULL);
  135.     }
  136.     memset(cur, 0, sizeof(xmlNs));
  137.     cur->type = XML_LOCAL_NAMESPACE;
  138.     if (href != NULL)
  139. cur->href = xmlStrdup(href); 
  140.     if (prefix != NULL)
  141. cur->prefix = xmlStrdup(prefix); 
  142.     /*
  143.      * Add it at the end to preserve parsing order ...
  144.      * and checks for existing use of the prefix
  145.      */
  146.     if (node != NULL) {
  147. if (node->nsDef == NULL) {
  148.     node->nsDef = cur;
  149. } else {
  150.     xmlNsPtr prev = node->nsDef;
  151.     if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
  152. (!xmlStrcmp(prev->prefix, cur->prefix))) {
  153. xmlFreeNs(cur);
  154. return(NULL);
  155.     }    
  156.     while (prev->next != NULL) {
  157.         prev = prev->next;
  158. if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
  159.     (!xmlStrcmp(prev->prefix, cur->prefix))) {
  160.     xmlFreeNs(cur);
  161.     return(NULL);
  162. }    
  163.     }
  164.     prev->next = cur;
  165. }
  166.     }
  167.     return(cur);
  168. }
  169. /**
  170.  * xmlNewGlobalNs:
  171.  * @doc:  the document carrying the namespace
  172.  * @href:  the URI associated
  173.  * @prefix:  the prefix for the namespace
  174.  *
  175.  * Creation of a Namespace, the old way using PI and without scoping
  176.  *   DEPRECATED !!!
  177.  * It now create a namespace on the root element of the document if found.
  178.  * Returns NULL this functionnality had been removed
  179.  */
  180. xmlNsPtr
  181. xmlNewGlobalNs(xmlDocPtr doc, const xmlChar *href, const xmlChar *prefix) {
  182.     xmlNodePtr root;
  183.     xmlNsPtr cur;
  184.  
  185.     root = xmlDocGetRootElement(doc);
  186.     if (root != NULL)
  187. return(xmlNewNs(root, href, prefix));
  188.     /*
  189.      * if there is no root element yet, create an old Namespace type
  190.      * and it will be moved to the root at save time.
  191.      */
  192.     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
  193.     if (cur == NULL) {
  194.         fprintf(stderr, "xmlNewGlobalNs : malloc failedn");
  195. return(NULL);
  196.     }
  197.     memset(cur, 0, sizeof(xmlNs));
  198.     cur->type = XML_GLOBAL_NAMESPACE;
  199.     if (href != NULL)
  200. cur->href = xmlStrdup(href); 
  201.     if (prefix != NULL)
  202. cur->prefix = xmlStrdup(prefix); 
  203.     /*
  204.      * Add it at the end to preserve parsing order ...
  205.      */
  206.     if (doc != NULL) {
  207. if (doc->oldNs == NULL) {
  208.     doc->oldNs = cur;
  209. } else {
  210.     xmlNsPtr prev = doc->oldNs;
  211.     while (prev->next != NULL) prev = prev->next;
  212.     prev->next = cur;
  213. }
  214.     }
  215.   return(NULL);
  216. }
  217. /**
  218.  * xmlSetNs:
  219.  * @node:  a node in the document
  220.  * @ns:  a namespace pointer
  221.  *
  222.  * Associate a namespace to a node, a posteriori.
  223.  */
  224. void
  225. xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
  226.     if (node == NULL) {
  227. #ifdef DEBUG_TREE
  228.         fprintf(stderr, "xmlSetNs: node == NULLn");
  229. #endif
  230. return;
  231.     }
  232.     node->ns = ns;
  233. }
  234. /**
  235.  * xmlFreeNs:
  236.  * @cur:  the namespace pointer
  237.  *
  238.  * Free up the structures associated to a namespace
  239.  */
  240. void
  241. xmlFreeNs(xmlNsPtr cur) {
  242.     if (cur == NULL) {
  243. #ifdef DEBUG_TREE
  244.         fprintf(stderr, "xmlFreeNs : ns == NULLn");
  245. #endif
  246. return;
  247.     }
  248.     if (cur->href != NULL) xmlFree((char *) cur->href);
  249.     if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
  250.     memset(cur, -1, sizeof(xmlNs));
  251.     xmlFree(cur);
  252. }
  253. /**
  254.  * xmlFreeNsList:
  255.  * @cur:  the first namespace pointer
  256.  *
  257.  * Free up all the structures associated to the chained namespaces.
  258.  */
  259. void
  260. xmlFreeNsList(xmlNsPtr cur) {
  261.     xmlNsPtr next;
  262.     if (cur == NULL) {
  263. #ifdef DEBUG_TREE
  264.         fprintf(stderr, "xmlFreeNsList : ns == NULLn");
  265. #endif
  266. return;
  267.     }
  268.     while (cur != NULL) {
  269.         next = cur->next;
  270.         xmlFreeNs(cur);
  271. cur = next;
  272.     }
  273. }
  274. /**
  275.  * xmlNewDtd:
  276.  * @doc:  the document pointer
  277.  * @name:  the DTD name
  278.  * @ExternalID:  the external ID
  279.  * @SystemID:  the system ID
  280.  *
  281.  * Creation of a new DTD for the external subset. To create an
  282.  * internal subset, use xmlCreateIntSubset().
  283.  *
  284.  * Returns a pointer to the new DTD structure
  285.  */
  286. xmlDtdPtr
  287. xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
  288.                     const xmlChar *ExternalID, const xmlChar *SystemID) {
  289.     xmlDtdPtr cur;
  290.     if ((doc != NULL) && (doc->extSubset != NULL)) {
  291. #ifdef DEBUG_TREE
  292.         fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %sn",
  293.     /* !!! */ (char *) name, doc->name,
  294.     /* !!! */ (char *)doc->extSubset->name);
  295. #endif
  296. return(NULL);
  297.     }
  298.     /*
  299.      * Allocate a new DTD and fill the fields.
  300.      */
  301.     cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
  302.     if (cur == NULL) {
  303.         fprintf(stderr, "xmlNewDtd : malloc failedn");
  304. return(NULL);
  305.     }
  306.     memset(cur, 0 , sizeof(xmlDtd));
  307.     cur->type = XML_DTD_NODE;
  308.     if (name != NULL)
  309. cur->name = xmlStrdup(name); 
  310.     if (ExternalID != NULL)
  311. cur->ExternalID = xmlStrdup(ExternalID); 
  312.     if (SystemID != NULL)
  313. cur->SystemID = xmlStrdup(SystemID); 
  314.     if (doc != NULL)
  315. doc->extSubset = cur;
  316.     cur->doc = doc;
  317.     return(cur);
  318. }
  319. /**
  320.  * xmlGetIntSubset:
  321.  * @doc:  the document pointer
  322.  *
  323.  * Get the internal subset of a document
  324.  * Returns a pointer to the DTD structure or NULL if not found
  325.  */
  326. xmlDtdPtr
  327. xmlGetIntSubset(xmlDocPtr doc) {
  328.     xmlNodePtr cur;
  329.     if (doc == NULL)
  330. return(NULL);
  331.     cur = doc->children;
  332.     while (cur != NULL) {
  333. if (cur->type == XML_DTD_NODE)
  334.     return((xmlDtdPtr) cur);
  335. cur = cur->next;
  336.     }
  337.     return((xmlDtdPtr) doc->intSubset);
  338. }
  339. /**
  340.  * xmlCreateIntSubset:
  341.  * @doc:  the document pointer
  342.  * @name:  the DTD name
  343.  * @ExternalID:  the external ID
  344.  * @SystemID:  the system ID
  345.  *
  346.  * Create the internal subset of a document
  347.  * Returns a pointer to the new DTD structure
  348.  */
  349. xmlDtdPtr
  350. xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
  351.                    const xmlChar *ExternalID, const xmlChar *SystemID) {
  352.     xmlDtdPtr cur;
  353.     if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
  354. #ifdef DEBUG_TREE
  355.         fprintf(stderr, 
  356.      "xmlCreateIntSubset(): document %s already have an internal subsetn",
  357.     doc->name);
  358. #endif
  359. return(NULL);
  360.     }
  361.     /*
  362.      * Allocate a new DTD and fill the fields.
  363.      */
  364.     cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
  365.     if (cur == NULL) {
  366.         fprintf(stderr, "xmlNewDtd : malloc failedn");
  367. return(NULL);
  368.     }
  369.     memset(cur, 0, sizeof(xmlDtd));
  370.     cur->type = XML_DTD_NODE;
  371.     if (name != NULL)
  372. cur->name = xmlStrdup(name); 
  373.     if (ExternalID != NULL)
  374. cur->ExternalID = xmlStrdup(ExternalID); 
  375.     if (SystemID != NULL)
  376. cur->SystemID = xmlStrdup(SystemID); 
  377.     if (doc != NULL) {
  378. doc->intSubset = cur;
  379. cur->parent = doc;
  380. cur->doc = doc;
  381. if (doc->children == NULL) {
  382.     doc->children = (xmlNodePtr) cur;
  383.     doc->last = (xmlNodePtr) cur;
  384. } else {
  385.     xmlNodePtr prev;
  386.     prev = doc->last;
  387.     prev->next = (xmlNodePtr) cur;
  388.     cur->prev = prev;
  389.     doc->last = (xmlNodePtr) cur;
  390. }
  391.     }
  392.     return(cur);
  393. }
  394. /**
  395.  * xmlFreeDtd:
  396.  * @cur:  the DTD structure to free up
  397.  *
  398.  * Free a DTD structure.
  399.  */
  400. void
  401. xmlFreeDtd(xmlDtdPtr cur) {
  402.     if (cur == NULL) {
  403. #ifdef DEBUG_TREE
  404.         fprintf(stderr, "xmlFreeDtd : DTD == NULLn");
  405. #endif
  406. return;
  407.     }
  408.     if (cur->children != NULL) {
  409. xmlNodePtr next, c = cur->children;
  410. /*
  411.  * Cleanup all the DTD comments they are not in the Dtd
  412.  * indexes.
  413.  */
  414.         while (c != NULL) {
  415.     next = c->next;
  416.     if (c->type == XML_COMMENT_NODE) {
  417. xmlUnlinkNode(c);
  418. xmlFreeNode(c);
  419.     }
  420.     c = next;
  421. }
  422.     }
  423.     if (cur->name != NULL) xmlFree((char *) cur->name);
  424.     if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
  425.     if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
  426.     /* TODO !!! */
  427.     if (cur->notations != NULL)
  428.         xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
  429.     
  430.     if (cur->elements != NULL)
  431.         xmlFreeElementTable((xmlElementTablePtr) cur->elements);
  432.     if (cur->attributes != NULL)
  433.         xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
  434.     if (cur->entities != NULL)
  435.         xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
  436.     memset(cur, -1, sizeof(xmlDtd));
  437.     xmlFree(cur);
  438. }
  439. /**
  440.  * xmlNewDoc:
  441.  * @version:  xmlChar string giving the version of XML "1.0"
  442.  *
  443.  * Returns a new document
  444.  */
  445. xmlDocPtr
  446. xmlNewDoc(const xmlChar *version) {
  447.     xmlDocPtr cur;
  448.     if (version == NULL) {
  449. #ifdef DEBUG_TREE
  450.         fprintf(stderr, "xmlNewDoc : version == NULLn");
  451. #endif
  452. return(NULL);
  453.     }
  454.     /*
  455.      * Allocate a new document and fill the fields.
  456.      */
  457.     cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
  458.     if (cur == NULL) {
  459.         fprintf(stderr, "xmlNewDoc : malloc failedn");
  460. return(NULL);
  461.     }
  462.     memset(cur, 0, sizeof(xmlDoc));
  463.     cur->type = XML_DOCUMENT_NODE;
  464.     cur->version = xmlStrdup(version); 
  465.     cur->standalone = -1;
  466.     cur->compression = -1; /* not initialized */
  467.     cur->doc = cur;
  468.     return(cur);
  469. }
  470. /**
  471.  * xmlFreeDoc:
  472.  * @cur:  pointer to the document
  473.  * @:  
  474.  *
  475.  * Free up all the structures used by a document, tree included.
  476.  */
  477. void
  478. xmlFreeDoc(xmlDocPtr cur) {
  479.     if (cur == NULL) {
  480. #ifdef DEBUG_TREE
  481.         fprintf(stderr, "xmlFreeDoc : document == NULLn");
  482. #endif
  483. return;
  484.     }
  485.     if (cur->version != NULL) xmlFree((char *) cur->version);
  486.     if (cur->name != NULL) xmlFree((char *) cur->name);
  487.     if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
  488.     if (cur->children != NULL) xmlFreeNodeList(cur->children);
  489.     if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
  490.     if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
  491.     if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
  492.     if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
  493.     if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
  494.     if (cur->URL != NULL) xmlFree((char *) cur->URL);
  495.     memset(cur, -1, sizeof(xmlDoc));
  496.     xmlFree(cur);
  497. }
  498. /**
  499.  * xmlStringLenGetNodeList:
  500.  * @doc:  the document
  501.  * @value:  the value of the text
  502.  * @len:  the length of the string value
  503.  *
  504.  * Parse the value string and build the node list associated. Should
  505.  * produce a flat tree with only TEXTs and ENTITY_REFs.
  506.  * Returns a pointer to the first child
  507.  */
  508. xmlNodePtr
  509. xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
  510.     xmlNodePtr ret = NULL, last = NULL;
  511.     xmlNodePtr node;
  512.     xmlChar *val;
  513.     const xmlChar *cur = value;
  514.     const xmlChar *q;
  515.     xmlEntityPtr ent;
  516.     if (value == NULL) return(NULL);
  517.     q = cur;
  518.     while ((*cur != 0) && (cur - value < len)) {
  519. if (*cur == '&') {
  520.     /*
  521.      * Save the current text.
  522.      */
  523.             if (cur != q) {
  524. if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
  525.     xmlNodeAddContentLen(last, q, cur - q);
  526. } else {
  527.     node = xmlNewDocTextLen(doc, q, cur - q);
  528.     if (node == NULL) return(ret);
  529.     if (last == NULL)
  530. last = ret = node;
  531.     else {
  532. last->next = node;
  533. node->prev = last;
  534. last = node;
  535.     }
  536. }
  537.     }
  538.     /*
  539.      * Read the entity string
  540.      */
  541.     cur++;
  542.     q = cur;
  543.     while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
  544.     if ((*cur == 0) || (cur - value >= len)) {
  545. #ifdef DEBUG_TREE
  546.         fprintf(stderr,
  547.     "xmlStringLenGetNodeList: unterminated entity %30sn", q);
  548. #endif
  549.         return(ret);
  550.     }
  551.             if (cur != q) {
  552. /*
  553.  * Predefined entities don't generate nodes
  554.  */
  555. val = xmlStrndup(q, cur - q);
  556. ent = xmlGetDocEntity(doc, val);
  557. if ((ent != NULL) &&
  558.     (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
  559.     if (last == NULL) {
  560.         node = xmlNewDocText(doc, ent->content);
  561. last = ret = node;
  562.     } else
  563.         xmlNodeAddContent(last, ent->content);
  564.         
  565. } else {
  566.     /*
  567.      * Create a new REFERENCE_REF node
  568.      */
  569.     node = xmlNewReference(doc, val);
  570.     if (node == NULL) {
  571. if (val != NULL) xmlFree(val);
  572.         return(ret);
  573.     }
  574.     if (last == NULL)
  575. last = ret = node;
  576.     else {
  577. last->next = node;
  578. node->prev = last;
  579. last = node;
  580.     }
  581. }
  582. xmlFree(val);
  583.     }
  584.     cur++;
  585.     q = cur;
  586. } else 
  587.     cur++;
  588.     }
  589.     if (cur != q) {
  590.         /*
  591.  * Handle the last piece of text.
  592.  */
  593. if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
  594.     xmlNodeAddContentLen(last, q, cur - q);
  595. } else {
  596.     node = xmlNewDocTextLen(doc, q, cur - q);
  597.     if (node == NULL) return(ret);
  598.     if (last == NULL)
  599. last = ret = node;
  600.     else {
  601. last->next = node;
  602. node->prev = last;
  603. last = node;
  604.     }
  605. }
  606.     }
  607.     return(ret);
  608. }
  609. /**
  610.  * xmlStringGetNodeList:
  611.  * @doc:  the document
  612.  * @value:  the value of the attribute
  613.  *
  614.  * Parse the value string and build the node list associated. Should
  615.  * produce a flat tree with only TEXTs and ENTITY_REFs.
  616.  * Returns a pointer to the first child
  617.  */
  618. xmlNodePtr
  619. xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
  620.     xmlNodePtr ret = NULL, last = NULL;
  621.     xmlNodePtr node;
  622.     xmlChar *val;
  623.     const xmlChar *cur = value;
  624.     const xmlChar *q;
  625.     xmlEntityPtr ent;
  626.     if (value == NULL) return(NULL);
  627.     q = cur;
  628.     while (*cur != 0) {
  629. if (*cur == '&') {
  630.     /*
  631.      * Save the current text.
  632.      */
  633.             if (cur != q) {
  634. if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
  635.     xmlNodeAddContentLen(last, q, cur - q);
  636. } else {
  637.     node = xmlNewDocTextLen(doc, q, cur - q);
  638.     if (node == NULL) return(ret);
  639.     if (last == NULL)
  640. last = ret = node;
  641.     else {
  642. last->next = node;
  643. node->prev = last;
  644. last = node;
  645.     }
  646. }
  647.     }
  648.     /*
  649.      * Read the entity string
  650.      */
  651.     cur++;
  652.     q = cur;
  653.     while ((*cur != 0) && (*cur != ';')) cur++;
  654.     if (*cur == 0) {
  655. #ifdef DEBUG_TREE
  656.         fprintf(stderr,
  657.         "xmlStringGetNodeList: unterminated entity %30sn", q);
  658. #endif
  659.         return(ret);
  660.     }
  661.             if (cur != q) {
  662. /*
  663.  * Predefined entities don't generate nodes
  664.  */
  665. val = xmlStrndup(q, cur - q);
  666. ent = xmlGetDocEntity(doc, val);
  667. if ((ent != NULL) &&
  668.     (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
  669.     if (last == NULL) {
  670.         node = xmlNewDocText(doc, ent->content);
  671. last = ret = node;
  672.     } else
  673.         xmlNodeAddContent(last, ent->content);
  674.         
  675. } else {
  676.     /*
  677.      * Create a new REFERENCE_REF node
  678.      */
  679.     node = xmlNewReference(doc, val);
  680.     if (node == NULL) {
  681. if (val != NULL) xmlFree(val);
  682.         return(ret);
  683.     }
  684.     if (last == NULL)
  685. last = ret = node;
  686.     else {
  687. last->next = node;
  688. node->prev = last;
  689. last = node;
  690.     }
  691. }
  692. xmlFree(val);
  693.     }
  694.     cur++;
  695.     q = cur;
  696. } else 
  697.     cur++;
  698.     }
  699.     if (cur != q) {
  700.         /*
  701.  * Handle the last piece of text.
  702.  */
  703. if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
  704.     xmlNodeAddContentLen(last, q, cur - q);
  705. } else {
  706.     node = xmlNewDocTextLen(doc, q, cur - q);
  707.     if (node == NULL) return(ret);
  708.     if (last == NULL)
  709. last = ret = node;
  710.     else {
  711. last->next = node;
  712. node->prev = last;
  713. last = node;
  714.     }
  715. }
  716.     }
  717.     return(ret);
  718. }
  719. /**
  720.  * xmlNodeListGetString:
  721.  * @doc:  the document
  722.  * @list:  a Node list
  723.  * @inLine:  should we replace entity contents or show their external form
  724.  *
  725.  * Returns the string equivalent to the text contained in the Node list
  726.  * made of TEXTs and ENTITY_REFs
  727.  * Returns a pointer to the string copy, the calller must free it.
  728.  */
  729. xmlChar *
  730. xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
  731.     xmlNodePtr node = list;
  732.     xmlChar *ret = NULL;
  733.     xmlEntityPtr ent;
  734.     if (list == NULL) return(NULL);
  735.     while (node != NULL) {
  736.         if (node->type == XML_TEXT_NODE) {
  737.     if (inLine) {
  738. #ifndef XML_USE_BUFFER_CONTENT
  739. ret = xmlStrcat(ret, node->content);
  740. #else
  741. ret = xmlStrcat(ret, xmlBufferContent(node->content));
  742. #endif
  743.     } else {
  744.         xmlChar *buffer;
  745. #ifndef XML_USE_BUFFER_CONTENT
  746. buffer = xmlEncodeEntitiesReentrant(doc, node->content);
  747. #else
  748. buffer = xmlEncodeEntitiesReentrant(doc,
  749.     xmlBufferContent(node->content));
  750. #endif
  751. if (buffer != NULL) {
  752.     ret = xmlStrcat(ret, buffer);
  753.     xmlFree(buffer);
  754. }
  755.             }
  756. } else if (node->type == XML_ENTITY_REF_NODE) {
  757.     if (inLine) {
  758. ent = xmlGetDocEntity(doc, node->name);
  759. if (ent != NULL)
  760.     ret = xmlStrcat(ret, ent->content);
  761. else {
  762. #ifndef XML_USE_BUFFER_CONTENT
  763.     ret = xmlStrcat(ret, node->content);
  764. #else
  765.     ret = xmlStrcat(ret, xmlBufferContent(node->content));
  766. #endif
  767. }    
  768.             } else {
  769.         xmlChar buf[2];
  770. buf[0] = '&'; buf[1] = 0;
  771. ret = xmlStrncat(ret, buf, 1);
  772. ret = xmlStrcat(ret, node->name);
  773. buf[0] = ';'; buf[1] = 0;
  774. ret = xmlStrncat(ret, buf, 1);
  775.     }
  776. }
  777. #if 0
  778. else {
  779.     fprintf(stderr, "xmlGetNodeListString : invalide node type %dn",
  780.             node->type);
  781. }
  782. #endif
  783. node = node->next;
  784.     }
  785.     return(ret);
  786. }
  787. /**
  788.  * xmlNewProp:
  789.  * @node:  the holding node
  790.  * @name:  the name of the attribute
  791.  * @value:  the value of the attribute
  792.  *
  793.  * Create a new property carried by a node.
  794.  * Returns a pointer to the attribute
  795.  */
  796. xmlAttrPtr
  797. xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
  798.     xmlAttrPtr cur;
  799.     if (name == NULL) {
  800. #ifdef DEBUG_TREE
  801.         fprintf(stderr, "xmlNewProp : name == NULLn");
  802. #endif
  803. return(NULL);
  804.     }
  805.     /*
  806.      * Allocate a new property and fill the fields.
  807.      */
  808.     cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
  809.     if (cur == NULL) {
  810.         fprintf(stderr, "xmlNewProp : malloc failedn");
  811. return(NULL);
  812.     }
  813.     memset(cur, 0, sizeof(xmlAttr));
  814.     cur->type = XML_ATTRIBUTE_NODE;
  815.     cur->parent = node; 
  816.     cur->name = xmlStrdup(name);
  817.     if (value != NULL) {
  818. xmlChar *buffer;
  819. xmlNodePtr tmp;
  820. buffer = xmlEncodeEntitiesReentrant(node->doc, value);
  821. cur->children = xmlStringGetNodeList(node->doc, buffer);
  822. tmp = cur->children;
  823. while (tmp != NULL) {
  824.     tmp->parent = (xmlNodePtr) cur;
  825.     if (tmp->next == NULL)
  826. cur->last = tmp;
  827.     tmp = tmp->next;
  828. }
  829. xmlFree(buffer);
  830.     }
  831.     /*
  832.      * Add it at the end to preserve parsing order ...
  833.      */
  834.     if (node != NULL) {
  835. if (node->properties == NULL) {
  836.     node->properties = cur;
  837. } else {
  838.     xmlAttrPtr prev = node->properties;
  839.     while (prev->next != NULL) prev = prev->next;
  840.     prev->next = cur;
  841.     cur->prev = prev;
  842. }
  843.     }
  844.     return(cur);
  845. }
  846. /**
  847.  * xmlNewNsProp:
  848.  * @node:  the holding node
  849.  * @ns:  the namespace
  850.  * @name:  the name of the attribute
  851.  * @value:  the value of the attribute
  852.  *
  853.  * Create a new property tagged with a namespace and carried by a node.
  854.  * Returns a pointer to the attribute
  855.  */
  856. xmlAttrPtr
  857. xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
  858.            const xmlChar *value) {
  859.     xmlAttrPtr cur;
  860.     if (name == NULL) {
  861. #ifdef DEBUG_TREE
  862.         fprintf(stderr, "xmlNewProp : name == NULLn");
  863. #endif
  864. return(NULL);
  865.     }
  866.     /*
  867.      * Allocate a new property and fill the fields.
  868.      */
  869.     cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
  870.     if (cur == NULL) {
  871.         fprintf(stderr, "xmlNewProp : malloc failedn");
  872. return(NULL);
  873.     }
  874.     memset(cur, 0, sizeof(xmlAttr));
  875.     cur->type = XML_ATTRIBUTE_NODE;
  876.     cur->parent = node; 
  877.     if (node != NULL)
  878. cur->doc = node->doc; 
  879.     cur->ns = ns;
  880.     cur->name = xmlStrdup(name);
  881.     if (value != NULL) {
  882. xmlChar *buffer;
  883. xmlNodePtr tmp;
  884. buffer = xmlEncodeEntitiesReentrant(node->doc, value);
  885. cur->children = xmlStringGetNodeList(node->doc, buffer);
  886. tmp = cur->children;
  887. while (tmp != NULL) {
  888.     tmp->parent = (xmlNodePtr) cur;
  889.     if (tmp->next == NULL)
  890. cur->last = tmp;
  891.     tmp = tmp->next;
  892. }
  893. xmlFree(buffer);
  894.     }
  895.     /*
  896.      * Add it at the end to preserve parsing order ...
  897.      */
  898.     if (node != NULL) {
  899. if (node->properties == NULL) {
  900.     node->properties = cur;
  901. } else {
  902.     xmlAttrPtr prev = node->properties;
  903.     while (prev->next != NULL) prev = prev->next;
  904.     prev->next = cur;
  905.     cur->prev = prev;
  906. }
  907.     }
  908.     return(cur);
  909. }
  910. /**
  911.  * xmlNewDocProp:
  912.  * @doc:  the document
  913.  * @name:  the name of the attribute
  914.  * @value:  the value of the attribute
  915.  *
  916.  * Create a new property carried by a document.
  917.  * Returns a pointer to the attribute
  918.  */
  919. xmlAttrPtr
  920. xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
  921.     xmlAttrPtr cur;
  922.     if (name == NULL) {
  923. #ifdef DEBUG_TREE
  924.         fprintf(stderr, "xmlNewProp : name == NULLn");
  925. #endif
  926. return(NULL);
  927.     }
  928.     /*
  929.      * Allocate a new property and fill the fields.
  930.      */
  931.     cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
  932.     if (cur == NULL) {
  933.         fprintf(stderr, "xmlNewProp : malloc failedn");
  934. return(NULL);
  935.     }
  936.     memset(cur, 0, sizeof(xmlAttr));
  937.     cur->type = XML_ATTRIBUTE_NODE;
  938.     cur->name = xmlStrdup(name);
  939.     cur->doc = doc; 
  940.     if (value != NULL)
  941. cur->children = xmlStringGetNodeList(doc, value);
  942.     return(cur);
  943. }
  944. /**
  945.  * xmlFreePropList:
  946.  * @cur:  the first property in the list
  947.  *
  948.  * Free a property and all its siblings, all the children are freed too.
  949.  */
  950. void
  951. xmlFreePropList(xmlAttrPtr cur) {
  952.     xmlAttrPtr next;
  953.     if (cur == NULL) {
  954. #ifdef DEBUG_TREE
  955.         fprintf(stderr, "xmlFreePropList : property == NULLn");
  956. #endif
  957. return;
  958.     }
  959.     while (cur != NULL) {
  960.         next = cur->next;
  961.         xmlFreeProp(cur);
  962. cur = next;
  963.     }
  964. }
  965. /**
  966.  * xmlFreeProp:
  967.  * @cur:  an attribute
  968.  *
  969.  * Free one attribute, all the content is freed too
  970.  */
  971. void
  972. xmlFreeProp(xmlAttrPtr cur) {
  973.     if (cur == NULL) {
  974. #ifdef DEBUG_TREE
  975.         fprintf(stderr, "xmlFreeProp : property == NULLn");
  976. #endif
  977. return;
  978.     }
  979.     /* Check for ID removal -> leading to invalid references ! */
  980.     if ((cur->parent != NULL) && 
  981.         (xmlIsID(cur->parent->doc, cur->parent, cur)))
  982.         xmlRemoveID(cur->parent->doc, cur);
  983.     if (cur->name != NULL) xmlFree((char *) cur->name);
  984.     if (cur->children != NULL) xmlFreeNodeList(cur->children);
  985.     memset(cur, -1, sizeof(xmlAttr));
  986.     xmlFree(cur);
  987. }
  988. /**
  989.  * xmlRemoveProp:
  990.  * @cur:  an attribute
  991.  *
  992.  * Unlink and free one attribute, all the content is freed too
  993.  * Note this doesn't work for namespace definition attributes
  994.  *
  995.  * Returns 0 if success and -1 in case of error.
  996.  */
  997. int
  998. xmlRemoveProp(xmlAttrPtr cur) {
  999.     xmlAttrPtr tmp;
  1000.     if (cur == NULL) {
  1001. #ifdef DEBUG_TREE
  1002.         fprintf(stderr, "xmlRemoveProp : cur == NULLn");
  1003. #endif
  1004. return(-1);
  1005.     }
  1006.     if (cur->parent == NULL) {
  1007. #ifdef DEBUG_TREE
  1008.         fprintf(stderr, "xmlRemoveProp : cur->parent == NULLn");
  1009. #endif
  1010. return(-1);
  1011.     }
  1012.     tmp = cur->parent->properties;
  1013.     if (tmp == cur) {
  1014.         cur->parent->properties = cur->next;
  1015. xmlFreeProp(cur);
  1016. return(0);
  1017.     }
  1018.     while (tmp != NULL) {
  1019. if (tmp->next == cur) {
  1020.     tmp->next = cur->next;
  1021.     if (tmp->next != NULL)
  1022. tmp->next->prev = tmp;
  1023.     xmlFreeProp(cur);
  1024.     return(0);
  1025. }
  1026.         tmp = tmp->next;
  1027.     }
  1028. #ifdef DEBUG_TREE
  1029.     fprintf(stderr, "xmlRemoveProp : attribute not owned by its noden");
  1030. #endif
  1031.     return(-1);
  1032. }
  1033. /**
  1034.  * xmlNewPI:
  1035.  * @name:  the processing instruction name
  1036.  * @content:  the PI content
  1037.  *
  1038.  * Creation of a processing instruction element.
  1039.  * Returns a pointer to the new node object.
  1040.  */
  1041. xmlNodePtr
  1042. xmlNewPI(const xmlChar *name, const xmlChar *content) {
  1043.     xmlNodePtr cur;
  1044.     if (name == NULL) {
  1045. #ifdef DEBUG_TREE
  1046.         fprintf(stderr, "xmlNewPI : name == NULLn");
  1047. #endif
  1048. return(NULL);
  1049.     }
  1050.     /*
  1051.      * Allocate a new node and fill the fields.
  1052.      */
  1053.     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
  1054.     if (cur == NULL) {
  1055.         fprintf(stderr, "xmlNewPI : malloc failedn");
  1056. return(NULL);
  1057.     }
  1058.     memset(cur, 0, sizeof(xmlNode));
  1059.     cur->type = XML_PI_NODE;
  1060.     cur->name = xmlStrdup(name);
  1061.     if (content != NULL) {
  1062. #ifndef XML_USE_BUFFER_CONTENT
  1063. cur->content = xmlStrdup(content);
  1064. #else
  1065. cur->content = xmlBufferCreateSize(0);
  1066. xmlBufferSetAllocationScheme(cur->content,
  1067.                      xmlGetBufferAllocationScheme());
  1068. xmlBufferAdd(cur->content, content, -1);
  1069. #endif
  1070.     }
  1071.     return(cur);
  1072. }
  1073. /**
  1074.  * xmlNewNode:
  1075.  * @ns:  namespace if any
  1076.  * @name:  the node name
  1077.  *
  1078.  * Creation of a new node element. @ns and @content are optionnal (NULL).
  1079.  * If content is non NULL, a child list containing the TEXTs and
  1080.  * ENTITY_REFs node will be created.
  1081.  * Returns a pointer to the new node object.
  1082.  */
  1083. xmlNodePtr
  1084. xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
  1085.     xmlNodePtr cur;
  1086.     if (name == NULL) {
  1087. #ifdef DEBUG_TREE
  1088.         fprintf(stderr, "xmlNewNode : name == NULLn");
  1089. #endif
  1090. return(NULL);
  1091.     }
  1092.     /*
  1093.      * Allocate a new node and fill the fields.
  1094.      */
  1095.     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
  1096.     if (cur == NULL) {
  1097.         fprintf(stderr, "xmlNewNode : malloc failedn");
  1098. return(NULL);
  1099.     }
  1100.     memset(cur, 0, sizeof(xmlNode));
  1101.     cur->type = XML_ELEMENT_NODE;
  1102.     
  1103.     cur->name = xmlStrdup(name);
  1104.     cur->ns = ns;
  1105.     return(cur);
  1106. }
  1107. /**
  1108.  * xmlNewDocNode:
  1109.  * @doc:  the document
  1110.  * @ns:  namespace if any
  1111.  * @name:  the node name
  1112.  * @content:  the XML text content if any
  1113.  *
  1114.  * Creation of a new node element within a document. @ns and @content
  1115.  * are optionnal (NULL).
  1116.  * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
  1117.  *       references, but XML special chars need to be escaped first by using
  1118.  *       xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
  1119.  *       need entities support.
  1120.  *
  1121.  * Returns a pointer to the new node object.
  1122.  */
  1123. xmlNodePtr
  1124. xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
  1125.               const xmlChar *name, const xmlChar *content) {
  1126.     xmlNodePtr cur;
  1127.     cur = xmlNewNode(ns, name);
  1128.     if (cur != NULL) {
  1129.         cur->doc = doc;
  1130. if (content != NULL) {
  1131.     cur->children = xmlStringGetNodeList(doc, content);
  1132.     UPDATE_LAST_CHILD(cur)
  1133. }
  1134.     }
  1135.     return(cur);
  1136. }
  1137. /**
  1138.  * xmlNewDocRawNode:
  1139.  * @doc:  the document
  1140.  * @ns:  namespace if any
  1141.  * @name:  the node name
  1142.  * @content:  the text content if any
  1143.  *
  1144.  * Creation of a new node element within a document. @ns and @content
  1145.  * are optionnal (NULL).
  1146.  *
  1147.  * Returns a pointer to the new node object.
  1148.  */
  1149. xmlNodePtr
  1150. xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
  1151.                  const xmlChar *name, const xmlChar *content) {
  1152.     xmlNodePtr cur;
  1153.     cur = xmlNewNode(ns, name);
  1154.     if (cur != NULL) {
  1155.         cur->doc = doc;
  1156. if (content != NULL) {
  1157.     cur->children = xmlNewDocText(doc, content);
  1158.     UPDATE_LAST_CHILD(cur)
  1159. }
  1160.     }
  1161.     return(cur);
  1162. }
  1163. /**
  1164.  * xmlNewDocFragment:
  1165.  * @doc:  the document owning the fragment
  1166.  *
  1167.  * Creation of a new Fragment node.
  1168.  * Returns a pointer to the new node object.
  1169.  */
  1170. xmlNodePtr
  1171. xmlNewDocFragment(xmlDocPtr doc) {
  1172.     xmlNodePtr cur;
  1173.     /*
  1174.      * Allocate a new DocumentFragment node and fill the fields.
  1175.      */
  1176.     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
  1177.     if (cur == NULL) {
  1178.         fprintf(stderr, "xmlNewDocFragment : malloc failedn");
  1179. return(NULL);
  1180.     }
  1181.     memset(cur, 0, sizeof(xmlNode));
  1182.     cur->type = XML_DOCUMENT_FRAG_NODE;
  1183.     cur->doc = doc;
  1184.     return(cur);
  1185. }
  1186. /**
  1187.  * xmlNewText:
  1188.  * @content:  the text content
  1189.  *
  1190.  * Creation of a new text node.
  1191.  * Returns a pointer to the new node object.
  1192.  */
  1193. xmlNodePtr
  1194. xmlNewText(const xmlChar *content) {
  1195.     xmlNodePtr cur;
  1196.     /*
  1197.      * Allocate a new node and fill the fields.
  1198.      */
  1199.     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
  1200.     if (cur == NULL) {
  1201.         fprintf(stderr, "xmlNewText : malloc failedn");
  1202. return(NULL);
  1203.     }
  1204.     memset(cur, 0, sizeof(xmlNode));
  1205.     cur->type = XML_TEXT_NODE;
  1206.     cur->name = xmlStrdup(xmlStringText);
  1207.     if (content != NULL) {
  1208. #ifndef XML_USE_BUFFER_CONTENT
  1209. cur->content = xmlStrdup(content);
  1210. #else
  1211. cur->content = xmlBufferCreateSize(0);
  1212. xmlBufferSetAllocationScheme(cur->content,
  1213.                      xmlGetBufferAllocationScheme());
  1214. xmlBufferAdd(cur->content, content, -1);
  1215. #endif
  1216.     }
  1217.     return(cur);
  1218. }
  1219. /**
  1220.  * xmlNewTextChild:
  1221.  * @parent:  the parent node
  1222.  * @ns:  a namespace if any
  1223.  * @name:  the name of the child
  1224.  * @content:  the text content of the child if any.
  1225.  *
  1226.  * Creation of a new child element, added at the end of @parent children list.
  1227.  * @ns and @content parameters are optionnal (NULL). If content is non NULL,
  1228.  * a child TEXT node will be created containing the string content.
  1229.  *
  1230.  * Returns a pointer to the new node object.
  1231.  */
  1232. xmlNodePtr
  1233. xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
  1234.             const xmlChar *name, const xmlChar *content) {
  1235.     xmlNodePtr cur, prev;
  1236.     if (parent == NULL) {
  1237. #ifdef DEBUG_TREE
  1238.         fprintf(stderr, "xmlNewTextChild : parent == NULLn");
  1239. #endif
  1240. return(NULL);
  1241.     }
  1242.     if (name == NULL) {
  1243. #ifdef DEBUG_TREE
  1244.         fprintf(stderr, "xmlNewTextChild : name == NULLn");
  1245. #endif
  1246. return(NULL);
  1247.     }
  1248.     /*
  1249.      * Allocate a new node
  1250.      */
  1251.     if (ns == NULL)
  1252. cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
  1253.     else
  1254. cur = xmlNewDocRawNode(parent->doc, ns, name, content);
  1255.     if (cur == NULL) return(NULL);
  1256.     /*
  1257.      * add the new element at the end of the children list.
  1258.      */
  1259.     cur->type = XML_ELEMENT_NODE;
  1260.     cur->parent = parent;
  1261.     cur->doc = parent->doc;
  1262.     if (parent->children == NULL) {
  1263.         parent->children = cur;
  1264. parent->last = cur;
  1265.     } else {
  1266.         prev = parent->last;
  1267. prev->next = cur;
  1268. cur->prev = prev;
  1269. parent->last = cur;
  1270.     }
  1271.     return(cur);
  1272. }
  1273. /**
  1274.  * xmlNewCharRef:
  1275.  * @doc: the document
  1276.  * @name:  the char ref string, starting with # or "&# ... ;"
  1277.  *
  1278.  * Creation of a new character reference node.
  1279.  * Returns a pointer to the new node object.
  1280.  */
  1281. xmlNodePtr
  1282. xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
  1283.     xmlNodePtr cur;
  1284.     /*
  1285.      * Allocate a new node and fill the fields.
  1286.      */
  1287.     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
  1288.     if (cur == NULL) {
  1289.         fprintf(stderr, "xmlNewText : malloc failedn");
  1290. return(NULL);
  1291.     }
  1292.     memset(cur, 0, sizeof(xmlNode));
  1293.     cur->type = XML_ENTITY_REF_NODE;
  1294.     cur->doc = doc;
  1295.     if (name[0] == '&') {
  1296.         int len;
  1297.         name++;
  1298. len = xmlStrlen(name);
  1299. if (name[len - 1] == ';')
  1300.     cur->name = xmlStrndup(name, len - 1);
  1301. else
  1302.     cur->name = xmlStrndup(name, len);
  1303.     } else
  1304. cur->name = xmlStrdup(name);
  1305.     return(cur);
  1306. }
  1307. /**
  1308.  * xmlNewReference:
  1309.  * @doc: the document
  1310.  * @name:  the reference name, or the reference string with & and ;
  1311.  *
  1312.  * Creation of a new reference node.
  1313.  * Returns a pointer to the new node object.
  1314.  */
  1315. xmlNodePtr
  1316. xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
  1317.     xmlNodePtr cur;
  1318.     xmlEntityPtr ent;
  1319.     /*
  1320.      * Allocate a new node and fill the fields.
  1321.      */
  1322.     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
  1323.     if (cur == NULL) {
  1324.         fprintf(stderr, "xmlNewText : malloc failedn");
  1325. return(NULL);
  1326.     }
  1327.     memset(cur, 0, sizeof(xmlNode));
  1328.     cur->type = XML_ENTITY_REF_NODE;
  1329.     cur->doc = doc;
  1330.     if (name[0] == '&') {
  1331.         int len;
  1332.         name++;
  1333. len = xmlStrlen(name);
  1334. if (name[len - 1] == ';')
  1335.     cur->name = xmlStrndup(name, len - 1);
  1336. else
  1337.     cur->name = xmlStrndup(name, len);
  1338.     } else
  1339. cur->name = xmlStrdup(name);
  1340.     ent = xmlGetDocEntity(doc, cur->name);
  1341.     if (ent != NULL) {
  1342. #ifndef XML_USE_BUFFER_CONTENT
  1343. cur->content = ent->content;
  1344. #else
  1345. /*
  1346.  * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
  1347.  * a copy of this pointer.  Let's hope we don't manipulate it
  1348.  * later 
  1349.  */
  1350. cur->content = xmlBufferCreateSize(0);
  1351. xmlBufferSetAllocationScheme(cur->content,
  1352.                      xmlGetBufferAllocationScheme());
  1353. if (ent->content != NULL)
  1354.     xmlBufferAdd(cur->content, ent->content, -1);
  1355. #endif
  1356. cur->children = (xmlNodePtr) ent;
  1357.     }
  1358.     return(cur);
  1359. }
  1360. /**
  1361.  * xmlNewDocText:
  1362.  * @doc: the document
  1363.  * @content:  the text content
  1364.  *
  1365.  * Creation of a new text node within a document.
  1366.  * Returns a pointer to the new node object.
  1367.  */
  1368. xmlNodePtr
  1369. xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
  1370.     xmlNodePtr cur;
  1371.     cur = xmlNewText(content);
  1372.     if (cur != NULL) cur->doc = doc;
  1373.     return(cur);
  1374. }
  1375. /**
  1376.  * xmlNewTextLen:
  1377.  * @content:  the text content
  1378.  * @len:  the text len.
  1379.  *
  1380.  * Creation of a new text node with an extra parameter for the content's lenght
  1381.  * Returns a pointer to the new node object.
  1382.  */
  1383. xmlNodePtr
  1384. xmlNewTextLen(const xmlChar *content, int len) {
  1385.     xmlNodePtr cur;
  1386.     /*
  1387.      * Allocate a new node and fill the fields.
  1388.      */
  1389.     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
  1390.     if (cur == NULL) {
  1391.         fprintf(stderr, "xmlNewText : malloc failedn");
  1392. return(NULL);
  1393.     }
  1394.     memset(cur, 0, sizeof(xmlNode));
  1395.     cur->type = XML_TEXT_NODE;
  1396.     cur->name = xmlStrdup(xmlStringText);
  1397.     if (content != NULL) {
  1398. #ifndef XML_USE_BUFFER_CONTENT
  1399. cur->content = xmlStrndup(content, len);
  1400. #else
  1401. cur->content = xmlBufferCreateSize(len);
  1402. xmlBufferSetAllocationScheme(cur->content,
  1403.                      xmlGetBufferAllocationScheme());
  1404. xmlBufferAdd(cur->content, content, len);
  1405. #endif
  1406.     }
  1407.     return(cur);
  1408. }
  1409. /**
  1410.  * xmlNewDocTextLen:
  1411.  * @doc: the document
  1412.  * @content:  the text content
  1413.  * @len:  the text len.
  1414.  *
  1415.  * Creation of a new text node with an extra content lenght parameter. The
  1416.  * text node pertain to a given document.
  1417.  * Returns a pointer to the new node object.
  1418.  */
  1419. xmlNodePtr
  1420. xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
  1421.     xmlNodePtr cur;
  1422.     cur = xmlNewTextLen(content, len);
  1423.     if (cur != NULL) cur->doc = doc;
  1424.     return(cur);
  1425. }
  1426. /**
  1427.  * xmlNewComment:
  1428.  * @content:  the comment content
  1429.  *
  1430.  * Creation of a new node containing a comment.
  1431.  * Returns a pointer to the new node object.
  1432.  */
  1433. xmlNodePtr
  1434. xmlNewComment(const xmlChar *content) {
  1435.     xmlNodePtr cur;
  1436.     /*
  1437.      * Allocate a new node and fill the fields.
  1438.      */
  1439.     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
  1440.     if (cur == NULL) {
  1441.         fprintf(stderr, "xmlNewComment : malloc failedn");
  1442. return(NULL);
  1443.     }
  1444.     memset(cur, 0, sizeof(xmlNode));
  1445.     cur->type = XML_COMMENT_NODE;
  1446.     cur->name = xmlStrdup(xmlStringComment);
  1447.     if (content != NULL) {
  1448. #ifndef XML_USE_BUFFER_CONTENT
  1449. cur->content = xmlStrdup(content);
  1450. #else
  1451. cur->content = xmlBufferCreateSize(0);
  1452. xmlBufferSetAllocationScheme(cur->content,
  1453.                      xmlGetBufferAllocationScheme());
  1454. xmlBufferAdd(cur->content, content, -1);
  1455. #endif
  1456.     }
  1457.     return(cur);
  1458. }
  1459. /**
  1460.  * xmlNewCDataBlock:
  1461.  * @doc:  the document
  1462.  * @content:  the CData block content content
  1463.  * @len:  the length of the block
  1464.  *
  1465.  * Creation of a new node containing a CData block.
  1466.  * Returns a pointer to the new node object.
  1467.  */
  1468. xmlNodePtr
  1469. xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
  1470.     xmlNodePtr cur;
  1471.     /*
  1472.      * Allocate a new node and fill the fields.
  1473.      */
  1474.     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
  1475.     if (cur == NULL) {
  1476.         fprintf(stderr, "xmlNewCDataBlock : malloc failedn");
  1477. return(NULL);
  1478.     }
  1479.     memset(cur, 0, sizeof(xmlNode));
  1480.     cur->type = XML_CDATA_SECTION_NODE;
  1481.     if (content != NULL) {
  1482. #ifndef XML_USE_BUFFER_CONTENT
  1483. cur->content = xmlStrndup(content, len);
  1484. #else
  1485. cur->content = xmlBufferCreateSize(len);
  1486. xmlBufferSetAllocationScheme(cur->content,
  1487.                      xmlGetBufferAllocationScheme());
  1488. xmlBufferAdd(cur->content, content, len);
  1489. #endif
  1490.     }
  1491.     return(cur);
  1492. }
  1493. /**
  1494.  * xmlNewDocComment:
  1495.  * @doc:  the document
  1496.  * @content:  the comment content
  1497.  *
  1498.  * Creation of a new node containing a commentwithin a document.
  1499.  * Returns a pointer to the new node object.
  1500.  */
  1501. xmlNodePtr
  1502. xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
  1503.     xmlNodePtr cur;
  1504.     cur = xmlNewComment(content);
  1505.     if (cur != NULL) cur->doc = doc;
  1506.     return(cur);
  1507. }
  1508. /**
  1509.  * xmlNewChild:
  1510.  * @parent:  the parent node
  1511.  * @ns:  a namespace if any
  1512.  * @name:  the name of the child
  1513.  * @content:  the XML content of the child if any.
  1514.  *
  1515.  * Creation of a new child element, added at the end of @parent children list.
  1516.  * @ns and @content parameters are optionnal (NULL). If content is non NULL,
  1517.  * a child list containing the TEXTs and ENTITY_REFs node will be created.
  1518.  * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
  1519.  *       references, but XML special chars need to be escaped first by using
  1520.  *       xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
  1521.  *       support is not needed.
  1522.  *
  1523.  * Returns a pointer to the new node object.
  1524.  */
  1525. xmlNodePtr
  1526. xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
  1527.             const xmlChar *name, const xmlChar *content) {
  1528.     xmlNodePtr cur, prev;
  1529.     if (parent == NULL) {
  1530. #ifdef DEBUG_TREE
  1531.         fprintf(stderr, "xmlNewChild : parent == NULLn");
  1532. #endif
  1533. return(NULL);
  1534.     }
  1535.     if (name == NULL) {
  1536. #ifdef DEBUG_TREE
  1537.         fprintf(stderr, "xmlNewChild : name == NULLn");
  1538. #endif
  1539. return(NULL);
  1540.     }
  1541.     /*
  1542.      * Allocate a new node
  1543.      */
  1544.     if (ns == NULL)
  1545. cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
  1546.     else
  1547. cur = xmlNewDocNode(parent->doc, ns, name, content);
  1548.     if (cur == NULL) return(NULL);
  1549.     /*
  1550.      * add the new element at the end of the children list.
  1551.      */
  1552.     cur->type = XML_ELEMENT_NODE;
  1553.     cur->parent = parent;
  1554.     cur->doc = parent->doc;
  1555.     if (parent->children == NULL) {
  1556.         parent->children = cur;
  1557. parent->last = cur;
  1558.     } else {
  1559.         prev = parent->last;
  1560. prev->next = cur;
  1561. cur->prev = prev;
  1562. parent->last = cur;
  1563.     }
  1564.     return(cur);
  1565. }
  1566. /**
  1567.  * xmlAddNextSibling:
  1568.  * @cur:  the child node
  1569.  * @elem:  the new node
  1570.  *
  1571.  * Add a new element @elem as the next siblings of @cur
  1572.  * If the new element was already inserted in a document it is
  1573.  * first unlinked from its existing context.
  1574.  *
  1575.  * Returns the new element or NULL in case of error.
  1576.  */
  1577. xmlNodePtr
  1578. xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
  1579.     if (cur == NULL) {
  1580. #ifdef DEBUG_TREE
  1581.         fprintf(stderr, "xmlAddNextSibling : cur == NULLn");
  1582. #endif
  1583. return(NULL);
  1584.     }
  1585.     if (elem == NULL) {
  1586. #ifdef DEBUG_TREE
  1587.         fprintf(stderr, "xmlAddNextSibling : elem == NULLn");
  1588. #endif
  1589. return(NULL);
  1590.     }
  1591.     xmlUnlinkNode(elem);
  1592.     elem->doc = cur->doc;
  1593.     elem->parent = cur->parent;
  1594.     elem->prev = cur;
  1595.     elem->next = cur->next;
  1596.     cur->next = elem;
  1597.     if (elem->next != NULL)
  1598. elem->next->prev = elem;
  1599.     if ((elem->parent != NULL) && (elem->parent->last == cur))
  1600. elem->parent->last = elem;
  1601.     return(elem);
  1602. }
  1603. /**
  1604.  * xmlAddPrevSibling:
  1605.  * @cur:  the child node
  1606.  * @elem:  the new node
  1607.  *
  1608.  * Add a new element @elem as the previous siblings of @cur
  1609.  * If the new element was already inserted in a document it is
  1610.  * first unlinked from its existing context.
  1611.  *
  1612.  * Returns the new element or NULL in case of error.
  1613.  */
  1614. xmlNodePtr
  1615. xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
  1616.     if (cur == NULL) {
  1617. #ifdef DEBUG_TREE
  1618.         fprintf(stderr, "xmlAddPrevSibling : cur == NULLn");
  1619. #endif
  1620. return(NULL);
  1621.     }
  1622.     if (elem == NULL) {
  1623. #ifdef DEBUG_TREE
  1624.         fprintf(stderr, "xmlAddPrevSibling : elem == NULLn");
  1625. #endif
  1626. return(NULL);
  1627.     }
  1628.     xmlUnlinkNode(elem);
  1629.     elem->doc = cur->doc;
  1630.     elem->parent = cur->parent;
  1631.     elem->next = cur;
  1632.     elem->prev = cur->prev;
  1633.     cur->prev = elem;
  1634.     if (elem->prev != NULL)
  1635. elem->prev->next = elem;
  1636.     if ((elem->parent != NULL) && (elem->parent->children == cur))
  1637. elem->parent->children = elem;
  1638.     return(elem);
  1639. }
  1640. /**
  1641.  * xmlAddSibling:
  1642.  * @cur:  the child node
  1643.  * @elem:  the new node
  1644.  *
  1645.  * Add a new element @elem to the list of siblings of @cur
  1646.  * If the new element was already inserted in a document it is
  1647.  * first unlinked from its existing context.
  1648.  *
  1649.  * Returns the new element or NULL in case of error.
  1650.  */
  1651. xmlNodePtr
  1652. xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
  1653.     xmlNodePtr parent;
  1654.     if (cur == NULL) {
  1655. #ifdef DEBUG_TREE
  1656.         fprintf(stderr, "xmlAddSibling : cur == NULLn");
  1657. #endif
  1658. return(NULL);
  1659.     }
  1660.     if (elem == NULL) {
  1661. #ifdef DEBUG_TREE
  1662.         fprintf(stderr, "xmlAddSibling : elem == NULLn");
  1663. #endif
  1664. return(NULL);
  1665.     }
  1666.     /*
  1667.      * Constant time is we can rely on the ->parent->last to find
  1668.      * the last sibling.
  1669.      */
  1670.     if ((cur->parent != NULL) && 
  1671. (cur->parent->children != NULL) &&
  1672. (cur->parent->last != NULL) &&
  1673. (cur->parent->last->next == NULL)) {
  1674. cur = cur->parent->last;
  1675.     } else {
  1676. while (cur->next != NULL) cur = cur->next;
  1677.     }
  1678.     xmlUnlinkNode(elem);
  1679.     if (elem->doc == NULL)
  1680. elem->doc = cur->doc; /* the parent may not be linked to a doc ! */
  1681.     parent = cur->parent;
  1682.     elem->prev = cur;
  1683.     elem->next = NULL;
  1684.     elem->parent = parent;
  1685.     cur->next = elem;
  1686.     if (parent != NULL)
  1687. parent->last = elem;
  1688.     return(elem);
  1689. }
  1690. /**
  1691.  * xmlAddChild:
  1692.  * @parent:  the parent node
  1693.  * @cur:  the child node
  1694.  *
  1695.  * Add a new child element, to @parent, at the end of the child list.
  1696.  * Returns the child or NULL in case of error.
  1697.  */
  1698. xmlNodePtr
  1699. xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
  1700.     xmlNodePtr prev;
  1701.     if (parent == NULL) {
  1702. #ifdef DEBUG_TREE
  1703.         fprintf(stderr, "xmlAddChild : parent == NULLn");
  1704. #endif
  1705. return(NULL);
  1706.     }
  1707.     if (cur == NULL) {
  1708. #ifdef DEBUG_TREE
  1709.         fprintf(stderr, "xmlAddChild : child == NULLn");
  1710. #endif
  1711. return(NULL);
  1712.     }
  1713.     if ((cur->doc != NULL) && (parent->doc != NULL) &&
  1714.         (cur->doc != parent->doc)) {
  1715. #ifdef DEBUG_TREE
  1716. fprintf(stderr, "Elements moved to a different documentn");
  1717. #endif
  1718.     }
  1719.     /*
  1720.      * add the new element at the end of the children list.
  1721.      */
  1722.     cur->parent = parent;
  1723.     cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
  1724.     /*
  1725.      * Handle the case where parent->content != NULL, in that case it will
  1726.      * create a intermediate TEXT node.
  1727.      */
  1728.     if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
  1729. (parent->content != NULL)) {
  1730.         xmlNodePtr text;
  1731. #ifndef XML_USE_BUFFER_CONTENT
  1732. text = xmlNewDocText(parent->doc, parent->content);
  1733. #else
  1734. text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
  1735. #endif
  1736. if (text != NULL) {
  1737.     text->next = parent->children;
  1738.     if (text->next != NULL)
  1739. text->next->prev = text;
  1740.     parent->children = text;
  1741.     UPDATE_LAST_CHILD(parent)
  1742. #ifndef XML_USE_BUFFER_CONTENT
  1743.     xmlFree(parent->content);
  1744. #else
  1745.     xmlBufferFree(parent->content);
  1746. #endif
  1747.     parent->content = NULL;
  1748. }
  1749.     }
  1750.     if (parent->children == NULL) {
  1751.         parent->children = cur;
  1752. parent->last = cur;
  1753.     } else {
  1754.         prev = parent->last;
  1755. prev->next = cur;
  1756. cur->prev = prev;
  1757. parent->last = cur;
  1758.     }
  1759.     return(cur);
  1760. }
  1761. /**
  1762.  * xmlGetLastChild:
  1763.  * @parent:  the parent node
  1764.  *
  1765.  * Search the last child of a node.
  1766.  * Returns the last child or NULL if none.
  1767.  */
  1768. xmlNodePtr
  1769. xmlGetLastChild(xmlNodePtr parent) {
  1770.     if (parent == NULL) {
  1771. #ifdef DEBUG_TREE
  1772.         fprintf(stderr, "xmlGetLastChild : parent == NULLn");
  1773. #endif
  1774. return(NULL);
  1775.     }
  1776.     return(parent->last);
  1777. }
  1778. /**
  1779.  * xmlFreeNodeList:
  1780.  * @cur:  the first node in the list
  1781.  *
  1782.  * Free a node and all its siblings, this is a recursive behaviour, all
  1783.  * the children are freed too.
  1784.  */
  1785. void
  1786. xmlFreeNodeList(xmlNodePtr cur) {
  1787.     xmlNodePtr next;
  1788.     if (cur == NULL) {
  1789. #ifdef DEBUG_TREE
  1790.         fprintf(stderr, "xmlFreeNodeList : node == NULLn");
  1791. #endif
  1792. return;
  1793.     }
  1794.     while (cur != NULL) {
  1795.         next = cur->next;
  1796.         xmlFreeNode(cur);
  1797. cur = next;
  1798.     }
  1799. }
  1800. /**
  1801.  * xmlFreeNode:
  1802.  * @cur:  the node
  1803.  *
  1804.  * Free a node, this is a recursive behaviour, all the children are freed too.
  1805.  * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
  1806.  */
  1807. void
  1808. xmlFreeNode(xmlNodePtr cur) {
  1809.     if (cur == NULL) {
  1810. #ifdef DEBUG_TREE
  1811.         fprintf(stderr, "xmlFreeNode : node == NULLn");
  1812. #endif
  1813. return;
  1814.     }
  1815.     if (cur->type == XML_DTD_NODE)
  1816. return;
  1817.     cur->doc = NULL;
  1818.     cur->parent = NULL;
  1819.     cur->next = NULL;
  1820.     cur->prev = NULL;
  1821.     if ((cur->children != NULL) &&
  1822. (cur->type != XML_ENTITY_REF_NODE))
  1823. xmlFreeNodeList(cur->children);
  1824.     if (cur->properties != NULL) xmlFreePropList(cur->properties);
  1825.     if (cur->type != XML_ENTITY_REF_NODE)
  1826. #ifndef XML_USE_BUFFER_CONTENT
  1827. if (cur->content != NULL) xmlFree(cur->content);
  1828. #else
  1829.      if (cur->content != NULL) xmlBufferFree(cur->content);
  1830. #endif
  1831.     if (cur->name != NULL) xmlFree((char *) cur->name);
  1832.     if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
  1833.     memset(cur, -1, sizeof(xmlNode));
  1834.     xmlFree(cur);
  1835. }
  1836. /**
  1837.  * xmlUnlinkNode:
  1838.  * @cur:  the node
  1839.  *
  1840.  * Unlink a node from it's current context, the node is not freed
  1841.  */
  1842. void
  1843. xmlUnlinkNode(xmlNodePtr cur) {
  1844.     if (cur == NULL) {
  1845. #ifdef DEBUG_TREE
  1846.         fprintf(stderr, "xmlUnlinkNode : node == NULLn");
  1847. #endif
  1848. return;
  1849.     }
  1850.     if ((cur->parent != NULL) && (cur->parent->children == cur))
  1851.         cur->parent->children = cur->next;
  1852.     if ((cur->parent != NULL) && (cur->parent->last == cur))
  1853.         cur->parent->last = cur->prev;
  1854.     if (cur->next != NULL)
  1855.         cur->next->prev = cur->prev;
  1856.     if (cur->prev != NULL)
  1857.         cur->prev->next = cur->next;
  1858.     cur->next = cur->prev = NULL;
  1859.     cur->parent = NULL;
  1860. }
  1861. /**
  1862.  * xmlReplaceNode:
  1863.  * @old:  the old node
  1864.  * @cur:  the node
  1865.  *
  1866.  * Unlink the old node from it's current context, prune the new one
  1867.  * at the same place. If cur was already inserted in a document it is
  1868.  * first unlinked from its existing context.
  1869.  *
  1870.  * Returns the old node
  1871.  */
  1872. xmlNodePtr
  1873. xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
  1874.     if (old == NULL) {
  1875. #ifdef DEBUG_TREE
  1876.         fprintf(stderr, "xmlReplaceNode : old == NULLn");
  1877. #endif
  1878. return(NULL);
  1879.     }
  1880.     if (cur == NULL) {
  1881. xmlUnlinkNode(old);
  1882. return(old);
  1883.     }
  1884.     xmlUnlinkNode(cur);
  1885.     cur->doc = old->doc;
  1886.     cur->parent = old->parent;
  1887.     cur->next = old->next;
  1888.     if (cur->next != NULL)
  1889. cur->next->prev = cur;
  1890.     cur->prev = old->prev;
  1891.     if (cur->prev != NULL)
  1892. cur->prev->next = cur;
  1893.     if (cur->parent != NULL) {
  1894. if (cur->parent->children == old)
  1895.     cur->parent->children = cur;
  1896. if (cur->parent->last == old)
  1897.     cur->parent->last = cur;
  1898.     }
  1899.     old->next = old->prev = NULL;
  1900.     old->parent = NULL;
  1901.     return(old);
  1902. }
  1903. /************************************************************************
  1904.  * *
  1905.  * Copy operations *
  1906.  * *
  1907.  ************************************************************************/
  1908.  
  1909. /**
  1910.  * xmlCopyNamespace:
  1911.  * @cur:  the namespace
  1912.  *
  1913.  * Do a copy of the namespace.
  1914.  *
  1915.  * Returns: a new xmlNsPtr, or NULL in case of error.
  1916.  */
  1917. xmlNsPtr
  1918. xmlCopyNamespace(xmlNsPtr cur) {
  1919.     xmlNsPtr ret;
  1920.     if (cur == NULL) return(NULL);
  1921.     switch (cur->type) {
  1922.         case XML_GLOBAL_NAMESPACE:
  1923.     ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
  1924.     break;
  1925. case XML_LOCAL_NAMESPACE:
  1926.     ret = xmlNewNs(NULL, cur->href, cur->prefix);
  1927.     break;
  1928. default:
  1929. #ifdef DEBUG_TREE
  1930.     fprintf(stderr, "xmlCopyNamespace: unknown type %dn", cur->type);
  1931. #endif
  1932.     return(NULL);
  1933.     }
  1934.     return(ret);
  1935. }
  1936. /**
  1937.  * xmlCopyNamespaceList:
  1938.  * @cur:  the first namespace
  1939.  *
  1940.  * Do a copy of an namespace list.
  1941.  *
  1942.  * Returns: a new xmlNsPtr, or NULL in case of error.
  1943.  */
  1944. xmlNsPtr
  1945. xmlCopyNamespaceList(xmlNsPtr cur) {
  1946.     xmlNsPtr ret = NULL;
  1947.     xmlNsPtr p = NULL,q;
  1948.     while (cur != NULL) {
  1949.         q = xmlCopyNamespace(cur);
  1950. if (p == NULL) {
  1951.     ret = p = q;
  1952. } else {
  1953.     p->next = q;
  1954.     p = q;
  1955. }
  1956. cur = cur->next;
  1957.     }
  1958.     return(ret);
  1959. }
  1960. /**
  1961.  * xmlCopyProp:
  1962.  * @target:  the element where the attribute will be grafted
  1963.  * @cur:  the attribute
  1964.  *
  1965.  * Do a copy of the attribute.
  1966.  *
  1967.  * Returns: a new xmlAttrPtr, or NULL in case of error.
  1968.  */
  1969. xmlAttrPtr
  1970. xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
  1971.     xmlAttrPtr ret;
  1972.     if (cur == NULL) return(NULL);
  1973.     if (cur->parent != NULL)
  1974. ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
  1975.     else if (cur->children != NULL)
  1976. ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
  1977.     else
  1978. ret = xmlNewDocProp(NULL, cur->name, NULL);
  1979.     if (ret == NULL) return(NULL);
  1980.     ret->parent = target;
  1981.     
  1982.     if ((cur->ns != NULL) && (target != NULL)) {
  1983.         xmlNsPtr ns;
  1984. ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
  1985. ret->ns = ns;
  1986.     } else
  1987.         ret->ns = NULL;
  1988.     if (cur->children != NULL)
  1989. ret->children = xmlCopyNodeList(cur->children);
  1990.     return(ret);
  1991. }
  1992. /**
  1993.  * xmlCopyPropList:
  1994.  * @target:  the element where the attributes will be grafted
  1995.  * @cur:  the first attribute
  1996.  *
  1997.  * Do a copy of an attribute list.
  1998.  *
  1999.  * Returns: a new xmlAttrPtr, or NULL in case of error.
  2000.  */
  2001. xmlAttrPtr
  2002. xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
  2003.     xmlAttrPtr ret = NULL;
  2004.     xmlAttrPtr p = NULL,q;
  2005.     while (cur != NULL) {
  2006.         q = xmlCopyProp(target, cur);
  2007. if (p == NULL) {
  2008.     ret = p = q;
  2009. } else {
  2010.     p->next = q;
  2011.     q->prev = p;
  2012.     p = q;
  2013. }
  2014. cur = cur->next;
  2015.     }
  2016.     return(ret);
  2017. }
  2018. /*
  2019.  * NOTE abeut the CopyNode operations !
  2020.  *
  2021.  * They are splitted into external and internal parts for one
  2022.  * tricky reason: namespaces. Doing a direct copy of a node
  2023.  * say RPM:Copyright without changing the namespace pointer to
  2024.  * something else can produce stale links. One way to do it is
  2025.  * to keep a reference counter but this doesn't work as soon
  2026.  * as one move the element or the subtree out of the scope of
  2027.  * the existing namespace. The actual solution seems to add
  2028.  * a copy of the namespace at the top of the copied tree if
  2029.  * not available in the subtree.
  2030.  * Hence two functions, the public front-end call the inner ones
  2031.  */
  2032. static xmlNodePtr
  2033. xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
  2034. static xmlNodePtr
  2035. xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
  2036.                   int recursive) {
  2037.     xmlNodePtr ret;
  2038.     if (node == NULL) return(NULL);
  2039.     /*
  2040.      * Allocate a new node and fill the fields.
  2041.      */
  2042.     ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
  2043.     if (ret == NULL) {
  2044.         fprintf(stderr, "xmlStaticCopyNode : malloc failedn");
  2045. return(NULL);
  2046.     }
  2047.     memset(ret, 0, sizeof(xmlNode));
  2048.     ret->type = node->type;
  2049.     ret->doc = doc;
  2050.     ret->parent = parent; 
  2051.     if (node->name != NULL)
  2052. ret->name = xmlStrdup(node->name);
  2053.     if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
  2054. #ifndef XML_USE_BUFFER_CONTENT
  2055. ret->content = xmlStrdup(node->content);
  2056. #else
  2057. ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
  2058. xmlBufferSetAllocationScheme(ret->content,
  2059.                      xmlGetBufferAllocationScheme());
  2060. xmlBufferAdd(ret->content,
  2061.      xmlBufferContent(node->content),
  2062.      xmlBufferLength(node->content));
  2063. #endif
  2064.     }
  2065.     if (parent != NULL)
  2066.         xmlAddChild(parent, ret);
  2067.     
  2068.     if (!recursive) return(ret);
  2069.     if (node->nsDef != NULL)
  2070.         ret->nsDef = xmlCopyNamespaceList(node->nsDef);
  2071.     if (node->ns != NULL) {
  2072.         xmlNsPtr ns;
  2073. ns = xmlSearchNs(doc, ret, node->ns->prefix);
  2074. if (ns == NULL) {
  2075.     /*
  2076.      * Humm, we are copying an element whose namespace is defined
  2077.      * out of the new tree scope. Search it in the original tree
  2078.      * and add it at the top of the new tree
  2079.      */
  2080.     ns = xmlSearchNs(node->doc, node, node->ns->prefix);
  2081.     if (ns != NULL) {
  2082.         xmlNodePtr root = ret;
  2083. while (root->parent != NULL) root = root->parent;
  2084. xmlNewNs(root, ns->href, ns->prefix);
  2085.     }
  2086. } else {
  2087.     /*
  2088.      * reference the existing namespace definition in our own tree.
  2089.      */
  2090.     ret->ns = ns;
  2091. }
  2092.     }
  2093.     if (node->properties != NULL)
  2094.         ret->properties = xmlCopyPropList(ret, node->properties);
  2095.     if (node->children != NULL)
  2096.         ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
  2097.     UPDATE_LAST_CHILD(ret)
  2098.     return(ret);
  2099. }
  2100. static xmlNodePtr
  2101. xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
  2102.     xmlNodePtr ret = NULL;
  2103.     xmlNodePtr p = NULL,q;
  2104.     while (node != NULL) {
  2105.         q = xmlStaticCopyNode(node, doc, parent, 1);
  2106. if (parent == NULL) {
  2107.     if (ret == NULL) ret = q;
  2108. } else {
  2109.     if (ret == NULL) {
  2110. q->prev = NULL;
  2111. ret = p = q;
  2112.     } else {
  2113. p->next = q;
  2114. q->prev = p;
  2115. p = q;
  2116.     }
  2117. }
  2118. node = node->next;
  2119.     }
  2120.     return(ret);
  2121. }
  2122. /**
  2123.  * xmlCopyNode:
  2124.  * @node:  the node
  2125.  * @recursive:  if 1 do a recursive copy.
  2126.  *
  2127.  * Do a copy of the node.
  2128.  *
  2129.  * Returns: a new xmlNodePtr, or NULL in case of error.
  2130.  */
  2131. xmlNodePtr
  2132. xmlCopyNode(xmlNodePtr node, int recursive) {
  2133.     xmlNodePtr ret;
  2134.     ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
  2135.     return(ret);
  2136. }
  2137. /**
  2138.  * xmlCopyNodeList:
  2139.  * @node:  the first node in the list.
  2140.  *
  2141.  * Do a recursive copy of the node list.
  2142.  *
  2143.  * Returns: a new xmlNodePtr, or NULL in case of error.
  2144.  */
  2145. xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
  2146.     xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
  2147.     return(ret);
  2148. }
  2149. /**
  2150.  * xmlCopyElement:
  2151.  * @elem:  the element
  2152.  *
  2153.  * Do a copy of the element definition.
  2154.  *
  2155.  * Returns: a new xmlElementPtr, or NULL in case of error.
  2156. xmlElementPtr
  2157. xmlCopyElement(xmlElementPtr elem) {
  2158.     xmlElementPtr ret;
  2159.     if (elem == NULL) return(NULL);
  2160.     ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
  2161.     if (ret == NULL) return(NULL);
  2162.     if (!recursive) return(ret);
  2163.     if (elem->properties != NULL)
  2164.         ret->properties = xmlCopyPropList(elem->properties);
  2165.     
  2166.     if (elem->nsDef != NULL)
  2167.         ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
  2168.     if (elem->children != NULL)
  2169.         ret->children = xmlCopyElementList(elem->children);
  2170.     return(ret);
  2171. }
  2172.  */
  2173. /**
  2174.  * xmlCopyDtd:
  2175.  * @dtd:  the dtd
  2176.  *
  2177.  * Do a copy of the dtd.
  2178.  *
  2179.  * Returns: a new xmlDtdPtr, or NULL in case of error.
  2180.  */
  2181. xmlDtdPtr
  2182. xmlCopyDtd(xmlDtdPtr dtd) {
  2183.     xmlDtdPtr ret;
  2184.     if (dtd == NULL) return(NULL);
  2185.     ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
  2186.     if (ret == NULL) return(NULL);
  2187.     if (dtd->entities != NULL)
  2188.         ret->entities = (void *) xmlCopyEntitiesTable(
  2189.                     (xmlEntitiesTablePtr) dtd->entities);
  2190.     if (dtd->notations != NULL)
  2191.         ret->notations = (void *) xmlCopyNotationTable(
  2192.                     (xmlNotationTablePtr) dtd->notations);
  2193.     if (dtd->elements != NULL)
  2194.         ret->elements = (void *) xmlCopyElementTable(
  2195.                     (xmlElementTablePtr) dtd->elements);
  2196.     if (dtd->attributes != NULL)
  2197.         ret->attributes = (void *) xmlCopyAttributeTable(
  2198.                     (xmlAttributeTablePtr) dtd->attributes);
  2199.     return(ret);
  2200. }
  2201. /**
  2202.  * xmlCopyDoc:
  2203.  * @doc:  the document
  2204.  * @recursive:  if 1 do a recursive copy.
  2205.  *
  2206.  * Do a copy of the document info. If recursive, the content tree will
  2207.  * be copied too as well as Dtd, namespaces and entities.
  2208.  *
  2209.  * Returns: a new xmlDocPtr, or NULL in case of error.
  2210.  */
  2211. xmlDocPtr
  2212. xmlCopyDoc(xmlDocPtr doc, int recursive) {
  2213.     xmlDocPtr ret;
  2214.     if (doc == NULL) return(NULL);
  2215.     ret = xmlNewDoc(doc->version);
  2216.     if (ret == NULL) return(NULL);
  2217.     if (doc->name != NULL)
  2218.         ret->name = xmlMemStrdup(doc->name);
  2219.     if (doc->encoding != NULL)
  2220.         ret->encoding = xmlStrdup(doc->encoding);
  2221.     ret->compression = doc->compression;
  2222.     ret->standalone = doc->standalone;
  2223.     if (!recursive) return(ret);
  2224.     if (doc->intSubset != NULL)
  2225.         ret->intSubset = xmlCopyDtd(doc->intSubset);
  2226.     if (doc->oldNs != NULL)
  2227.         ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
  2228.     if (doc->children != NULL)
  2229.         ret->children = xmlStaticCopyNodeList(doc->children, ret, NULL);
  2230.     return(ret);
  2231. }
  2232. /************************************************************************
  2233.  * *
  2234.  * Content access functions *
  2235.  * *
  2236.  ************************************************************************/
  2237.  
  2238. /**
  2239.  * xmlDocGetRootElement:
  2240.  * @doc:  the document
  2241.  *
  2242.  * Get the root element of the document (doc->children is a list
  2243.  * containing possibly comments, PIs, etc ...).
  2244.  *
  2245.  * Returns the xmlNodePtr for the root or NULL
  2246.  */
  2247. xmlNodePtr
  2248. xmlDocGetRootElement(xmlDocPtr doc) {
  2249.     xmlNodePtr ret;
  2250.     if (doc == NULL) return(NULL);
  2251.     ret = doc->children;
  2252.     while (ret != NULL) {
  2253. if (ret->type == XML_ELEMENT_NODE)
  2254.     return(ret);
  2255.         ret = ret->next;
  2256.     }
  2257.     return(ret);
  2258. }
  2259.  
  2260. /**
  2261.  * xmlDocSetRootElement:
  2262.  * @doc:  the document
  2263.  * @root:  the new document root element
  2264.  *
  2265.  * Set the root element of the document (doc->children is a list
  2266.  * containing possibly comments, PIs, etc ...).
  2267.  *
  2268.  * Returns the old root element if any was found
  2269.  */
  2270. xmlNodePtr
  2271. xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
  2272.     xmlNodePtr old = NULL;
  2273.     if (doc == NULL) return(NULL);
  2274.     old = doc->children;
  2275.     while (old != NULL) {
  2276. if (old->type == XML_ELEMENT_NODE)
  2277.     break;
  2278.         old = old->next;
  2279.     }
  2280.     if (old == NULL) {
  2281. if (doc->children == NULL) {
  2282.     doc->children = root;
  2283. } else {
  2284.     xmlAddSibling(doc->children, root);
  2285. }
  2286.     } else {
  2287. xmlReplaceNode(old, root);
  2288.     }
  2289.     return(old);
  2290. }
  2291.  
  2292. /**
  2293.  * xmlNodeSetLang:
  2294.  * @cur:  the node being changed
  2295.  * @lang:  the langage description
  2296.  *
  2297.  * Set the language of a node, i.e. the values of the xml:lang
  2298.  * attribute.
  2299.  */
  2300. void
  2301. xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
  2302.     if (cur == NULL) return;
  2303.     switch(cur->type) {
  2304.         case XML_TEXT_NODE:
  2305.         case XML_CDATA_SECTION_NODE:
  2306.         case XML_COMMENT_NODE:
  2307.         case XML_DOCUMENT_NODE:
  2308.         case XML_DOCUMENT_TYPE_NODE:
  2309.         case XML_DOCUMENT_FRAG_NODE:
  2310.         case XML_NOTATION_NODE:
  2311.         case XML_HTML_DOCUMENT_NODE:
  2312.         case XML_DTD_NODE:
  2313.         case XML_ELEMENT_DECL:
  2314.         case XML_ATTRIBUTE_DECL:
  2315.         case XML_ENTITY_DECL:
  2316.     return;
  2317.         case XML_ELEMENT_NODE:
  2318.         case XML_ATTRIBUTE_NODE:
  2319.         case XML_PI_NODE:
  2320.         case XML_ENTITY_REF_NODE:
  2321.         case XML_ENTITY_NODE:
  2322.     break;
  2323.     }
  2324.     xmlSetProp(cur, BAD_CAST "xml:lang", lang);
  2325. }
  2326.  
  2327. /**
  2328.  * xmlNodeGetLang:
  2329.  * @cur:  the node being checked
  2330.  *
  2331.  * Searches the language of a node, i.e. the values of the xml:lang
  2332.  * attribute or the one carried by the nearest ancestor.
  2333.  *
  2334.  * Returns a pointer to the lang value, or NULL if not found
  2335.  *     It's up to the caller to free the memory.
  2336.  */
  2337. xmlChar *
  2338. xmlNodeGetLang(xmlNodePtr cur) {
  2339.     xmlChar *lang;
  2340.     while (cur != NULL) {
  2341.         lang = xmlGetProp(cur, BAD_CAST "xml:lang");
  2342. if (lang != NULL)
  2343.     return(lang);
  2344. cur = cur->parent;
  2345.     }
  2346.     return(NULL);
  2347. }
  2348.  
  2349. /**
  2350.  * xmlNodeGetSpacePreserve:
  2351.  * @cur:  the node being checked
  2352.  *
  2353.  * Searches the language of a node, i.e. the values of the xml:space
  2354.  * attribute or the one carried by the nearest ancestor.
  2355.  *
  2356.  * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
  2357.  */
  2358. int
  2359. xmlNodeGetSpacePreserve(xmlNodePtr cur) {
  2360.     xmlChar *space;
  2361.     while (cur != NULL) {
  2362.         space = xmlGetProp(cur, BAD_CAST "xml:space");
  2363. if (space != NULL) {
  2364.     if (!xmlStrcmp(space, BAD_CAST "preserve")) {
  2365. xmlFree(space);
  2366. return(1);
  2367.     }
  2368.     if (!xmlStrcmp(space, BAD_CAST "default")) {
  2369. xmlFree(space);
  2370. return(0);
  2371.     }
  2372.     xmlFree(space);
  2373. }
  2374. cur = cur->parent;
  2375.     }
  2376.     return(-1);
  2377. }
  2378.  
  2379. /**
  2380.  * xmlNodeSetName:
  2381.  * @cur:  the node being changed
  2382.  * @name:  the new tag name
  2383.  *
  2384.  * Searches the language of a node, i.e. the values of the xml:lang
  2385.  * attribute or the one carried by the nearest ancestor.
  2386.  */
  2387. void
  2388. xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
  2389.     if (cur == NULL) return;
  2390.     if (name == NULL) return;
  2391.     switch(cur->type) {
  2392.         case XML_TEXT_NODE:
  2393.         case XML_CDATA_SECTION_NODE:
  2394.         case XML_COMMENT_NODE:
  2395.         case XML_DOCUMENT_TYPE_NODE:
  2396.         case XML_DOCUMENT_FRAG_NODE:
  2397.         case XML_NOTATION_NODE:
  2398.         case XML_HTML_DOCUMENT_NODE:
  2399.     return;
  2400.         case XML_ELEMENT_NODE:
  2401.         case XML_ATTRIBUTE_NODE:
  2402.         case XML_PI_NODE:
  2403.         case XML_ENTITY_REF_NODE:
  2404.         case XML_ENTITY_NODE:
  2405.         case XML_DTD_NODE:
  2406.         case XML_DOCUMENT_NODE:
  2407.         case XML_ELEMENT_DECL:
  2408.         case XML_ATTRIBUTE_DECL:
  2409.         case XML_ENTITY_DECL:
  2410.     break;
  2411.     }
  2412.     if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
  2413.     cur->name = xmlStrdup(name);
  2414. }
  2415.  
  2416. /**
  2417.  * xmlNodeGetBase:
  2418.  * @doc:  the document the node pertains to
  2419.  * @cur:  the node being checked
  2420.  *
  2421.  * Searches for the BASE URL. The code should work on both XML
  2422.  * and HTML document even if base mechanisms are completely different.
  2423.  *
  2424.  * Returns a pointer to the base URL, or NULL if not found
  2425.  *     It's up to the caller to free the memory.
  2426.  */
  2427. xmlChar *
  2428. xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
  2429.     xmlChar *base;
  2430.     if ((cur == NULL) && (doc == NULL)) 
  2431.         return(NULL);
  2432.     if (doc == NULL) doc = cur->doc;
  2433.     if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
  2434.         cur = doc->children;
  2435. while ((cur != NULL) && (cur->name != NULL)) {
  2436.     if (cur->type != XML_ELEMENT_NODE) {
  2437.         cur = cur->next;
  2438. continue;
  2439.     }
  2440.     if ((!xmlStrcmp(cur->name, BAD_CAST "html")) ||
  2441.         (!xmlStrcmp(cur->name, BAD_CAST "HTML"))) {
  2442.         cur = cur->children;
  2443. continue;
  2444.     }
  2445.     if ((!xmlStrcmp(cur->name, BAD_CAST "head")) ||
  2446.         (!xmlStrcmp(cur->name, BAD_CAST "HEAD"))) {
  2447.         cur = cur->children;
  2448. continue;
  2449.     }
  2450.     if ((!xmlStrcmp(cur->name, BAD_CAST "base")) ||
  2451.         (!xmlStrcmp(cur->name, BAD_CAST "BASE"))) {
  2452.                 base = xmlGetProp(cur, BAD_CAST "href");
  2453. if (base != NULL) return(base);
  2454.                 return(xmlGetProp(cur, BAD_CAST "HREF"));
  2455.     }
  2456.     cur = cur->next;
  2457. }
  2458. if ((doc != NULL) && (doc->URL != NULL))
  2459.     return(xmlStrdup(doc->URL));
  2460. return(NULL);
  2461.     }
  2462.     while (cur != NULL) {
  2463.         base = xmlGetProp(cur, BAD_CAST "xml:base");
  2464. if (base != NULL)
  2465.     return(base);
  2466. cur = cur->parent;
  2467.     }
  2468.     if ((doc != NULL) && (doc->URL != NULL))
  2469. return(xmlStrdup(doc->URL));
  2470.     return(NULL);
  2471. }
  2472.  
  2473. /**
  2474.  * xmlNodeGetContent:
  2475.  * @cur:  the node being read
  2476.  *
  2477.  * Read the value of a node, this can be either the text carried
  2478.  * directly by this node if it's a TEXT node or the aggregate string
  2479.  * of the values carried by this node child's (TEXT and ENTITY_REF).
  2480.  * Entity references are substitued.
  2481.  * Returns a new xmlChar * or NULL if no content is available.
  2482.  *     It's up to the caller to free the memory.
  2483.  */
  2484. xmlChar *
  2485. xmlNodeGetContent(xmlNodePtr cur) {
  2486.     if (cur == NULL) return(NULL);
  2487.     switch (cur->type) {
  2488.         case XML_DOCUMENT_FRAG_NODE:
  2489.         case XML_ELEMENT_NODE:
  2490.             return(xmlNodeListGetString(cur->doc, cur->children, 1));
  2491.     break;
  2492.         case XML_ATTRIBUTE_NODE: {
  2493.     xmlAttrPtr attr = (xmlAttrPtr) cur;
  2494.     if (attr->parent != NULL)
  2495. return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
  2496.     else
  2497. return(xmlNodeListGetString(NULL, attr->children, 1));
  2498.     break;
  2499. }
  2500.         case XML_COMMENT_NODE:
  2501.         case XML_PI_NODE:
  2502.     if (cur->content != NULL)
  2503. #ifndef XML_USE_BUFFER_CONTENT
  2504.         return(xmlStrdup(cur->content));
  2505. #else
  2506.         return(xmlStrdup(xmlBufferContent(cur->content)));
  2507. #endif
  2508.     return(NULL);
  2509.         case XML_ENTITY_REF_NODE:
  2510.     /*
  2511.      * Locate the entity, and get it's content
  2512.      * @@@
  2513.      */
  2514.             return(NULL);
  2515.         case XML_ENTITY_NODE:
  2516.         case XML_DOCUMENT_NODE:
  2517.         case XML_HTML_DOCUMENT_NODE:
  2518.         case XML_DOCUMENT_TYPE_NODE:
  2519.         case XML_NOTATION_NODE:
  2520.         case XML_DTD_NODE:
  2521.     return(NULL);
  2522.         case XML_ELEMENT_DECL:
  2523.     /* TODO !!! */
  2524.     return(NULL);
  2525.         case XML_ATTRIBUTE_DECL:
  2526.     /* TODO !!! */
  2527.     return(NULL);
  2528.         case XML_ENTITY_DECL:
  2529.     /* TODO !!! */
  2530.     return(NULL);
  2531.         case XML_CDATA_SECTION_NODE:
  2532.         case XML_TEXT_NODE:
  2533.     if (cur->content != NULL)
  2534. #ifndef XML_USE_BUFFER_CONTENT
  2535. return(xmlStrdup(cur->content));
  2536. #else
  2537.         return(xmlStrdup(xmlBufferContent(cur->content)));
  2538. #endif
  2539.             return(NULL);
  2540.     }
  2541.     return(NULL);
  2542. }
  2543.  
  2544. /**
  2545.  * xmlNodeSetContent:
  2546.  * @cur:  the node being modified
  2547.  * @content:  the new value of the content
  2548.  *
  2549.  * Replace the content of a node.
  2550.  */
  2551. void
  2552. xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
  2553.     if (cur == NULL) {
  2554. #ifdef DEBUG_TREE
  2555.         fprintf(stderr, "xmlNodeSetContent : node == NULLn");
  2556. #endif
  2557. return;
  2558.     }
  2559.     switch (cur->type) {
  2560.         case XML_DOCUMENT_FRAG_NODE:
  2561.         case XML_ELEMENT_NODE:
  2562.     if (cur->content != NULL) {
  2563. #ifndef XML_USE_BUFFER_CONTENT
  2564.         xmlFree(cur->content);
  2565. #else
  2566. xmlBufferFree(cur->content);
  2567. #endif
  2568. cur->content = NULL;
  2569.     }
  2570.     if (cur->children != NULL) xmlFreeNodeList(cur->children);
  2571.     cur->children = xmlStringGetNodeList(cur->doc, content);
  2572.     UPDATE_LAST_CHILD(cur)
  2573.     break;
  2574.         case XML_ATTRIBUTE_NODE:
  2575.     break;
  2576.         case XML_TEXT_NODE:
  2577.         case XML_CDATA_SECTION_NODE:
  2578.         case XML_ENTITY_REF_NODE:
  2579.         case XML_ENTITY_NODE:
  2580.         case XML_PI_NODE:
  2581.         case XML_COMMENT_NODE:
  2582.     if (cur->content != NULL) {
  2583. #ifndef XML_USE_BUFFER_CONTENT
  2584. xmlFree(cur->content);
  2585. #else
  2586.         xmlBufferFree(cur->content);
  2587. #endif
  2588.     }
  2589.     if (cur->children != NULL) xmlFreeNodeList(cur->children);
  2590.     cur->last = cur->children = NULL;
  2591.     if (content != NULL) {
  2592. #ifndef XML_USE_BUFFER_CONTENT
  2593. cur->content = xmlStrdup(content);
  2594. #else
  2595. cur->content = xmlBufferCreateSize(0);
  2596. xmlBufferSetAllocationScheme(cur->content,
  2597.                      xmlGetBufferAllocationScheme());
  2598. xmlBufferAdd(cur->content, content, -1);
  2599. #endif
  2600.     } else 
  2601. cur->content = NULL;
  2602.     break;
  2603.         case XML_DOCUMENT_NODE:
  2604.         case XML_HTML_DOCUMENT_NODE:
  2605.         case XML_DOCUMENT_TYPE_NODE:
  2606.     break;
  2607.         case XML_NOTATION_NODE:
  2608.     break;
  2609.         case XML_DTD_NODE:
  2610.     break;
  2611.         case XML_ELEMENT_DECL:
  2612.     /* TODO !!! */
  2613.     break;
  2614.         case XML_ATTRIBUTE_DECL:
  2615.     /* TODO !!! */
  2616.     break;
  2617.         case XML_ENTITY_DECL:
  2618.     /* TODO !!! */
  2619.     break;
  2620.     }
  2621. }
  2622. /**
  2623.  * xmlNodeSetContentLen:
  2624.  * @cur:  the node being modified
  2625.  * @content:  the new value of the content
  2626.  * @len:  the size of @content
  2627.  *
  2628.  * Replace the content of a node.
  2629.  */
  2630. void
  2631. xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
  2632.     if (cur == NULL) {
  2633. #ifdef DEBUG_TREE
  2634.         fprintf(stderr, "xmlNodeSetContentLen : node == NULLn");
  2635. #endif
  2636. return;
  2637.     }
  2638.     switch (cur->type) {
  2639.         case XML_DOCUMENT_FRAG_NODE:
  2640.         case XML_ELEMENT_NODE:
  2641.     if (cur->content != NULL) {
  2642. #ifndef XML_USE_BUFFER_CONTENT
  2643.         xmlFree(cur->content);
  2644. #else
  2645. xmlBufferFree(cur->content);
  2646. #endif
  2647. cur->content = NULL;
  2648.     }
  2649.     if (cur->children != NULL) xmlFreeNodeList(cur->children);
  2650.     cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
  2651.     UPDATE_LAST_CHILD(cur)
  2652.     break;
  2653.         case XML_ATTRIBUTE_NODE:
  2654.     break;
  2655.         case XML_TEXT_NODE:
  2656.         case XML_CDATA_SECTION_NODE:
  2657.         case XML_ENTITY_REF_NODE:
  2658.         case XML_ENTITY_NODE:
  2659.         case XML_PI_NODE:
  2660.         case XML_COMMENT_NODE:
  2661.         case XML_NOTATION_NODE:
  2662.     if (cur->content != NULL) {
  2663. #ifndef XML_USE_BUFFER_CONTENT
  2664. xmlFree(cur->content);
  2665. #else
  2666.         xmlBufferFree(cur->content);
  2667. #endif
  2668.     }
  2669.     if (cur->children != NULL) xmlFreeNodeList(cur->children);
  2670.     cur->children = cur->last = NULL;
  2671.     if (content != NULL) {
  2672. #ifndef XML_USE_BUFFER_CONTENT
  2673. cur->content = xmlStrndup(content, len);
  2674. #else
  2675. cur->content = xmlBufferCreateSize(len);
  2676. xmlBufferSetAllocationScheme(cur->content,
  2677.                      xmlGetBufferAllocationScheme());
  2678. xmlBufferAdd(cur->content, content, len);
  2679. #endif
  2680.     } else 
  2681. cur->content = NULL;
  2682.     break;
  2683.         case XML_DOCUMENT_NODE:
  2684.         case XML_DTD_NODE:
  2685.         case XML_HTML_DOCUMENT_NODE:
  2686.         case XML_DOCUMENT_TYPE_NODE:
  2687.     break;
  2688.         case XML_ELEMENT_DECL:
  2689.     /* TODO !!! */
  2690.     break;
  2691.         case XML_ATTRIBUTE_DECL:
  2692.     /* TODO !!! */
  2693.     break;
  2694.         case XML_ENTITY_DECL:
  2695.     /* TODO !!! */
  2696.     break;
  2697.     }
  2698. }
  2699. /**
  2700.  * xmlNodeAddContentLen:
  2701.  * @cur:  the node being modified
  2702.  * @content:  extra content
  2703.  * @len:  the size of @content
  2704.  * 
  2705.  * Append the extra substring to the node content.
  2706.  */
  2707. void
  2708. xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
  2709.     if (cur == NULL) {
  2710. #ifdef DEBUG_TREE
  2711.         fprintf(stderr, "xmlNodeAddContentLen : node == NULLn");
  2712. #endif
  2713. return;
  2714.     }
  2715.     if (len <= 0) return;
  2716.     switch (cur->type) {
  2717.         case XML_DOCUMENT_FRAG_NODE:
  2718.         case XML_ELEMENT_NODE: {
  2719.     xmlNodePtr last = NULL, new;
  2720.     if (cur->children != NULL) {
  2721. last = cur->last;
  2722.     } else {
  2723.         if (cur->content != NULL) {
  2724. #ifndef XML_USE_BUFFER_CONTENT
  2725.     cur->children = xmlStringGetNodeList(cur->doc, cur->content);
  2726. #else
  2727.     cur->children = xmlStringGetNodeList(cur->doc,
  2728.                        xmlBufferContent(cur->content));
  2729. #endif
  2730.     UPDATE_LAST_CHILD(cur)
  2731. #ifndef XML_USE_BUFFER_CONTENT
  2732.     xmlFree(cur->content);
  2733. #else
  2734.     xmlBufferFree(cur->content);
  2735. #endif
  2736.     cur->content = NULL;
  2737.     last = cur->last;
  2738. }
  2739.     }
  2740.     new = xmlNewTextLen(content, len);
  2741.     if (new != NULL) {
  2742. xmlAddChild(cur, new);
  2743.         if ((last != NULL) && (last->next == new)) {
  2744.     xmlTextMerge(last, new);
  2745. }
  2746.     }
  2747.     break;
  2748. }
  2749.         case XML_ATTRIBUTE_NODE:
  2750.     break;
  2751.         case XML_TEXT_NODE:
  2752.         case XML_CDATA_SECTION_NODE:
  2753.         case XML_ENTITY_REF_NODE:
  2754.         case XML_ENTITY_NODE:
  2755.         case XML_PI_NODE:
  2756.         case XML_COMMENT_NODE:
  2757.         case XML_NOTATION_NODE:
  2758.     if (content != NULL) {
  2759. #ifndef XML_USE_BUFFER_CONTENT
  2760. cur->content = xmlStrncat(cur->content, content, len);
  2761. #else
  2762. xmlBufferAdd(cur->content, content, len);
  2763. #endif
  2764.             }
  2765.         case XML_DOCUMENT_NODE:
  2766.         case XML_DTD_NODE:
  2767.         case XML_HTML_DOCUMENT_NODE:
  2768.         case XML_DOCUMENT_TYPE_NODE:
  2769.     break;
  2770.         case XML_ELEMENT_DECL:
  2771.         case XML_ATTRIBUTE_DECL:
  2772.         case XML_ENTITY_DECL:
  2773.     break;
  2774.     }
  2775. }
  2776. /**
  2777.  * xmlNodeAddContent:
  2778.  * @cur:  the node being modified
  2779.  * @content:  extra content
  2780.  * 
  2781.  * Append the extra substring to the node content.
  2782.  */
  2783. void
  2784. xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
  2785.     int len;
  2786.     if (cur == NULL) {
  2787. #ifdef DEBUG_TREE
  2788.         fprintf(stderr, "xmlNodeAddContent : node == NULLn");
  2789. #endif
  2790. return;
  2791.     }
  2792.     if (content == NULL) return;
  2793.     len = xmlStrlen(content);
  2794.     xmlNodeAddContentLen(cur, content, len);
  2795. }
  2796. /**
  2797.  * xmlTextMerge:
  2798.  * @first:  the first text node
  2799.  * @second:  the second text node being merged
  2800.  * 
  2801.  * Merge two text nodes into one
  2802.  * Returns the first text node augmented
  2803.  */
  2804. xmlNodePtr
  2805. xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
  2806.     if (first == NULL) return(second);
  2807.     if (second == NULL) return(first);
  2808.     if (first->type != XML_TEXT_NODE) return(first);
  2809.     if (second->type != XML_TEXT_NODE) return(first);
  2810. #ifndef XML_USE_BUFFER_CONTENT
  2811.     xmlNodeAddContent(first, second->content);
  2812. #else
  2813.     xmlNodeAddContent(first, xmlBufferContent(second->content));
  2814. #endif
  2815.     xmlUnlinkNode(second);
  2816.     xmlFreeNode(second);
  2817.     return(first);
  2818. }
  2819. /**
  2820.  * xmlGetNsList:
  2821.  * @doc:  the document
  2822.  * @node:  the current node
  2823.  *
  2824.  * Search all the namespace applying to a given element.
  2825.  * Returns an NULL terminated array of all the xmlNsPtr found
  2826.  *         that need to be freed by the caller or NULL if no
  2827.  *         namespace if defined
  2828.  */
  2829. xmlNsPtr *
  2830. xmlGetNsList(xmlDocPtr doc, xmlNodePtr node) {
  2831.     xmlNsPtr cur;
  2832.     xmlNsPtr *ret = NULL;
  2833.     int nbns = 0;
  2834.     int maxns = 10;
  2835.     int i;
  2836.     while (node != NULL) {
  2837. cur = node->nsDef;
  2838. while (cur != NULL) {
  2839.     if (ret == NULL) {
  2840.         ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
  2841. if (ret == NULL) {
  2842.     fprintf(stderr, "xmlGetNsList : out of memory!n");
  2843.     return(NULL);
  2844. }
  2845. ret[nbns] = NULL;
  2846.     }
  2847.     for (i = 0;i < nbns;i++) {
  2848.         if ((cur->prefix == ret[i]->prefix) ||
  2849.     (!xmlStrcmp(cur->prefix, ret[i]->prefix))) break;
  2850.     }
  2851.     if (i >= nbns) {
  2852.         if (nbns >= maxns) {
  2853.     maxns *= 2;
  2854.     ret = (xmlNsPtr *) xmlRealloc(ret,
  2855.                          (maxns + 1) * sizeof(xmlNsPtr));
  2856.     if (ret == NULL) {
  2857. fprintf(stderr, "xmlGetNsList : realloc failed!n");
  2858. return(NULL);
  2859.     }
  2860. }
  2861. ret[nbns++] = cur;
  2862. ret[nbns] = NULL;
  2863.     }
  2864.     cur = cur->next;
  2865. }
  2866. node = node->parent;
  2867.     }
  2868.     return(ret);
  2869. }
  2870. /**
  2871.  * xmlSearchNs:
  2872.  * @doc:  the document
  2873.  * @node:  the current node
  2874.  * @nameSpace:  the namespace string
  2875.  *
  2876.  * Search a Ns registered under a given name space for a document.
  2877.  * recurse on the parents until it finds the defined namespace
  2878.  * or return NULL otherwise.
  2879.  * @nameSpace can be NULL, this is a search for the default namespace.
  2880.  * Returns the namespace pointer or NULL.
  2881.  */
  2882. xmlNsPtr
  2883. xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
  2884.     xmlNsPtr cur;
  2885.     if (node == NULL) return(NULL);
  2886.     while (node != NULL) {
  2887. if (node->type == XML_ELEMENT_NODE) {
  2888.     cur = node->nsDef;
  2889.     while (cur != NULL) {
  2890. if ((cur->prefix == NULL) && (nameSpace == NULL))
  2891.     return(cur);
  2892. if ((cur->prefix != NULL) && (nameSpace != NULL) &&
  2893.     (!xmlStrcmp(cur->prefix, nameSpace)))
  2894.     return(cur);
  2895. cur = cur->next;
  2896.     }
  2897. }
  2898. node = node->parent;
  2899.     }
  2900.     return(NULL);
  2901. }
  2902. /**
  2903.  * xmlSearchNsByHref:
  2904.  * @doc:  the document
  2905.  * @node:  the current node
  2906.  * @href:  the namespace value
  2907.  *
  2908.  * Search a Ns aliasing a given URI. Recurse on the parents until it finds
  2909.  * the defined namespace or return NULL otherwise.
  2910.  * Returns the namespace pointer or NULL.
  2911.  */
  2912. xmlNsPtr
  2913. xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
  2914.     xmlNsPtr cur;
  2915.     xmlNodePtr orig = node;
  2916.     if ((node == NULL) || (href == NULL)) return(NULL);
  2917.     while (node != NULL) {
  2918. cur = node->nsDef;
  2919. while (cur != NULL) {
  2920.     if ((cur->href != NULL) && (href != NULL) &&
  2921.         (!xmlStrcmp(cur->href, href))) {
  2922. /*
  2923.  * Check that the prefix is not shadowed between orig and node
  2924.  */
  2925. xmlNodePtr check = orig;
  2926. xmlNsPtr tst;
  2927. while (check != node) {
  2928.     tst = check->nsDef;
  2929.     while (tst != NULL) {
  2930. if ((tst->prefix == NULL) && (cur->prefix == NULL))
  2931.                     goto shadowed;
  2932. if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
  2933.     (!xmlStrcmp(tst->prefix, cur->prefix)))
  2934.                     goto shadowed;
  2935.         tst = tst->next;
  2936.     }
  2937. }
  2938. return(cur);
  2939.     }
  2940. shadowed:     
  2941.     cur = cur->next;
  2942. }
  2943. node = node->parent;
  2944.     }
  2945.     return(NULL);
  2946. }
  2947. /**
  2948.  * xmlNewReconciliedNs
  2949.  * @doc:  the document
  2950.  * @tree:  a node expected to hold the new namespace
  2951.  * @ns:  the original namespace
  2952.  *
  2953.  * This function tries to locate a namespace definition in a tree
  2954.  * ancestors, or create a new namespace definition node similar to
  2955.  * @ns trying to reuse the same prefix. However if the given prefix is
  2956.  * null (default namespace) or reused within the subtree defined by
  2957.  * @tree or on one of its ancestors then a new prefix is generated.
  2958.  * Returns the (new) namespace definition or NULL in case of error
  2959.  */
  2960. xmlNsPtr
  2961. xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
  2962.     xmlNsPtr def;
  2963.     xmlChar prefix[50];
  2964.     int counter = 1;
  2965.     if (tree == NULL) {
  2966. #ifdef DEBUG_TREE
  2967.         fprintf(stderr, "xmlNewReconciliedNs : tree == NULLn");
  2968. #endif
  2969. return(NULL);
  2970.     }
  2971.     if (ns == NULL) {
  2972. #ifdef DEBUG_TREE
  2973.         fprintf(stderr, "xmlNewReconciliedNs : ns == NULLn");
  2974. #endif
  2975. return(NULL);
  2976.     }
  2977.     /*
  2978.      * Search an existing namespace definition inherited.
  2979.      */
  2980.     def = xmlSearchNsByHref(doc, tree, ns->href);
  2981.     if (def != NULL)
  2982.         return(def);
  2983.     /*
  2984.      * Find a close prefix which is not already in use.
  2985.      * Let's strip namespace prefixes longer than 20 chars !
  2986.      */
  2987.     sprintf((char *) prefix, "%.20s", ns->prefix);
  2988.     def = xmlSearchNs(doc, tree, prefix);
  2989.     while (def != NULL) {
  2990.         if (counter > 1000) return(NULL);
  2991.         sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
  2992. def = xmlSearchNs(doc, tree, prefix);
  2993.     }
  2994.     /*
  2995.      * Ok, now we are ready to create a new one.
  2996.      */
  2997.     def = xmlNewNs(tree, ns->href, prefix);
  2998.     return(def);
  2999. }
  3000. /**
  3001.  * xmlReconciliateNs
  3002.  * @doc:  the document
  3003.  * @tree:  a node defining the subtree to reconciliate
  3004.  *
  3005.  * This function checks that all the namespaces declared within the given
  3006.  * tree are properly declared. This is needed for example after Copy or Cut
  3007.  * and then paste operations. The subtree may still hold pointers to
  3008.  * namespace declarations outside the subtree or invalid/masked. As much
  3009.  * as possible the function try tu reuse the existing namespaces found in
  3010.  * the new environment. If not possible the new namespaces are redeclared
  3011.  * on @tree at the top of the given subtree.
  3012.  * Returns the number of namespace declarations created or -1 in case of error.
  3013.  */
  3014. int
  3015. xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
  3016.     xmlNsPtr *oldNs = NULL;
  3017.     xmlNsPtr *newNs = NULL;
  3018.     int sizeCache = 0;
  3019.     int nbCache = 0;
  3020.     xmlNsPtr n;
  3021.     xmlNodePtr node = tree;
  3022.     xmlAttrPtr attr;
  3023.     int ret = 0, i;
  3024.     while (node != NULL) {
  3025.         /*
  3026.  * Reconciliate the node namespace
  3027.  */
  3028. if (node->ns != NULL) {
  3029.     /*
  3030.      * initialize the cache if needed
  3031.      */
  3032.     if (sizeCache == 0) {
  3033. sizeCache = 10;
  3034. oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
  3035.        sizeof(xmlNsPtr));
  3036. if (oldNs == NULL) {
  3037.     fprintf(stderr, "xmlReconciliateNs : memory pbmn");
  3038.     return(-1);
  3039. }
  3040. newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
  3041.        sizeof(xmlNsPtr));
  3042. if (newNs == NULL) {
  3043.     fprintf(stderr, "xmlReconciliateNs : memory pbmn");
  3044.     xmlFree(oldNs);
  3045.     return(-1);
  3046. }
  3047.     }
  3048.     for (i = 0;i < nbCache;i++) {
  3049.         if (oldNs[i] == node->ns) {
  3050.     node->ns = newNs[i];
  3051.     break;
  3052. }
  3053.     }
  3054.     if (i == nbCache) {
  3055.         /*
  3056.  * Ok we need to recreate a new namespace definition
  3057.  */
  3058. n = xmlNewReconciliedNs(doc, tree, node->ns);
  3059. if (n != NULL) { /* :-( what if else ??? */
  3060.     /*
  3061.      * check if we need to grow the cache buffers.
  3062.      */
  3063.     if (sizeCache <= nbCache) {
  3064.         sizeCache *= 2;
  3065. oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
  3066.                                sizeof(xmlNsPtr));
  3067.         if (oldNs == NULL) {
  3068.     fprintf(stderr, "xmlReconciliateNs : memory pbmn");
  3069.     xmlFree(newNs);
  3070.     return(-1);
  3071. }
  3072. newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
  3073.                                sizeof(xmlNsPtr));
  3074.         if (newNs == NULL) {
  3075.     fprintf(stderr, "xmlReconciliateNs : memory pbmn");
  3076.     xmlFree(oldNs);
  3077.     return(-1);
  3078. }
  3079.     }
  3080.     newNs[nbCache] = n;
  3081.     oldNs[nbCache++] = node->ns;
  3082.     node->ns = n;
  3083.                 }
  3084.     }
  3085. }
  3086. /*
  3087.  * now check for namespace hold by attributes on the node.
  3088.  */
  3089. attr = node->properties;
  3090. while (attr != NULL) {
  3091.     if (attr->ns != NULL) {
  3092. /*
  3093.  * initialize the cache if needed
  3094.  */
  3095. if (sizeCache == 0) {
  3096.     sizeCache = 10;
  3097.     oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
  3098.    sizeof(xmlNsPtr));
  3099.     if (oldNs == NULL) {
  3100. fprintf(stderr, "xmlReconciliateNs : memory pbmn");
  3101. return(-1);
  3102.     }
  3103.     newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
  3104.    sizeof(xmlNsPtr));
  3105.     if (newNs == NULL) {
  3106. fprintf(stderr, "xmlReconciliateNs : memory pbmn");
  3107. xmlFree(oldNs);
  3108. return(-1);
  3109.     }
  3110. }
  3111. for (i = 0;i < nbCache;i++) {
  3112.     if (oldNs[i] == attr->ns) {
  3113. node->ns = newNs[i];
  3114. break;
  3115.     }
  3116. }
  3117. if (i == nbCache) {
  3118.     /*
  3119.      * Ok we need to recreate a new namespace definition
  3120.      */
  3121.     n = xmlNewReconciliedNs(doc, tree, attr->ns);
  3122.     if (n != NULL) { /* :-( what if else ??? */
  3123. /*
  3124.  * check if we need to grow the cache buffers.
  3125.  */
  3126. if (sizeCache <= nbCache) {
  3127.     sizeCache *= 2;
  3128.     oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
  3129.    sizeof(xmlNsPtr));
  3130.     if (oldNs == NULL) {
  3131. fprintf(stderr,
  3132.         "xmlReconciliateNs : memory pbmn");
  3133. xmlFree(newNs);
  3134. return(-1);
  3135.     }
  3136.     newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
  3137.    sizeof(xmlNsPtr));
  3138.     if (newNs == NULL) {
  3139. fprintf(stderr,
  3140.         "xmlReconciliateNs : memory pbmn");
  3141. xmlFree(oldNs);
  3142. return(-1);
  3143.     }
  3144. }
  3145. newNs[nbCache] = n;
  3146. oldNs[nbCache++] = attr->ns;
  3147. attr->ns = n;
  3148.     }
  3149. }
  3150.     }
  3151.     attr = attr->next;
  3152. }
  3153. /*
  3154.  * Browse the full subtree, deep first
  3155.  */
  3156.         if (node->children != NULL) {
  3157.     /* deep first */
  3158.     node = node->children;
  3159. } else if ((node != tree) && (node->next != NULL)) {
  3160.     /* then siblings */
  3161.     node = node->next;
  3162. } else if (node != tree) {
  3163.     /* go up to parents->next if needed */
  3164.     while (node != tree) {
  3165.         if (node->parent != NULL)
  3166.     node = node->parent;
  3167. if ((node != tree) && (node->next != NULL)) {
  3168.     node = node->next;
  3169.     break;
  3170. }
  3171. if (node->parent == NULL) {
  3172.     node = NULL;
  3173.     break;
  3174. }
  3175.     }
  3176.     /* exit condition */
  3177.     if (node == tree) 
  3178.         node = NULL;
  3179. }
  3180.     }
  3181.     return(ret);
  3182. }
  3183. /**
  3184.  * xmlGetProp:
  3185.  * @node:  the node
  3186.  * @name:  the attribute name
  3187.  *
  3188.  * Search and get the value of an attribute associated to a node
  3189.  * This does the entity substitution.
  3190.  * This function looks in DTD attribute declaration for #FIXED or
  3191.  * default declaration values unless DTD use has been turned off.
  3192.  *
  3193.  * Returns the attribute value or NULL if not found.
  3194.  *     It's up to the caller to free the memory.
  3195.  */
  3196. xmlChar *
  3197. xmlGetProp(xmlNodePtr node, const xmlChar *name) {
  3198.     xmlAttrPtr prop;
  3199.     xmlDocPtr doc;
  3200.     if ((node == NULL) || (name == NULL)) return(NULL);
  3201.     /*
  3202.      * Check on the properties attached to the node
  3203.      */
  3204.     prop = node->properties;
  3205.     while (prop != NULL) {
  3206.         if (!xmlStrcmp(prop->name, name))  {
  3207.     xmlChar *ret;
  3208.     ret = xmlNodeListGetString(node->doc, prop->children, 1);
  3209.     if (ret == NULL) return(xmlStrdup((xmlChar *)""));
  3210.     return(ret);
  3211.         }
  3212. prop = prop->next;
  3213.     }
  3214.     if (!xmlCheckDTD) return(NULL);
  3215.     /*
  3216.      * Check if there is a default declaration in the internal
  3217.      * or external subsets
  3218.      */
  3219.     doc =  node->doc;
  3220.     if (doc != NULL) {
  3221.         xmlAttributePtr attrDecl;
  3222.         if (doc->intSubset != NULL) {
  3223.     attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
  3224.     if ((attrDecl == NULL) && (doc->extSubset != NULL))
  3225. attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
  3226.     if (attrDecl != NULL)
  3227. return(xmlStrdup(attrDecl->defaultValue));
  3228. }
  3229.     }
  3230.     return(NULL);
  3231. }
  3232. /**
  3233.  * xmlGetNsProp:
  3234.  * @node:  the node
  3235.  * @name:  the attribute name
  3236.  * @namespace:  the URI of the namespace
  3237.  *
  3238.  * Search and get the value of an attribute associated to a node
  3239.  * This attribute has to be anchored in the namespace specified.
  3240.  * This does the entity substitution.
  3241.  * This function looks in DTD attribute declaration for #FIXED or
  3242.  * default declaration values unless DTD use has been turned off.
  3243.  *
  3244.  * Returns the attribute value or NULL if not found.
  3245.  *     It's up to the caller to free the memory.
  3246.  */
  3247. xmlChar *
  3248. xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
  3249.     xmlAttrPtr prop = node->properties;
  3250.     xmlDocPtr doc;
  3251.     xmlNsPtr ns;
  3252.     if (namespace == NULL)
  3253. return(xmlGetProp(node, name));
  3254.     while (prop != NULL) {
  3255. /*
  3256.  * One need to have
  3257.  *   - same attribute names
  3258.  *   - and the attribute carrying that namespace
  3259.  *         or
  3260.  *         no namespace on the attribute and the element carrying it
  3261.  */
  3262.         if ((!xmlStrcmp(prop->name, name)) &&
  3263.     (((prop->ns == NULL) && (node->ns != NULL) &&
  3264.       (!xmlStrcmp(node->ns->href, namespace))) ||
  3265.      ((prop->ns != NULL) && (!xmlStrcmp(prop->ns->href, namespace))))) {
  3266.     xmlChar *ret;
  3267.     ret = xmlNodeListGetString(node->doc, prop->children, 1);
  3268.     if (ret == NULL) return(xmlStrdup((xmlChar *)""));
  3269.     return(ret);
  3270.         }
  3271. prop = prop->next;
  3272.     }
  3273.     if (!xmlCheckDTD) return(NULL);
  3274.     /*
  3275.      * Check if there is a default declaration in the internal
  3276.      * or external subsets
  3277.      */
  3278.     doc =  node->doc;
  3279.     if (doc != NULL) {
  3280.         xmlAttributePtr attrDecl;
  3281.         if (doc->intSubset != NULL) {
  3282.     attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
  3283.     if ((attrDecl == NULL) && (doc->extSubset != NULL))
  3284. attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
  3285.     if (attrDecl->prefix != NULL) {
  3286.         /*
  3287.  * The DTD declaration only allows a prefix search
  3288.  */
  3289. ns = xmlSearchNs(doc, node, attrDecl->prefix);
  3290. if ((ns != NULL) && (!xmlStrcmp(ns->href, namespace)))
  3291.     return(xmlStrdup(attrDecl->defaultValue));
  3292.     }
  3293. }
  3294.     }
  3295.     return(NULL);
  3296. }
  3297. /**
  3298.  * xmlSetProp:
  3299.  * @node:  the node
  3300.  * @name:  the attribute name
  3301.  * @value:  the attribute value
  3302.  *
  3303.  * Set (or reset) an attribute carried by a node.
  3304.  * Returns the attribute pointer.
  3305.  */
  3306. xmlAttrPtr
  3307. xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
  3308.     xmlAttrPtr prop = node->properties;
  3309.     while (prop != NULL) {
  3310.         if (!xmlStrcmp(prop->name, name)) {
  3311.     if (prop->children != NULL) 
  3312.         xmlFreeNodeList(prop->children);
  3313.     prop->children = NULL;
  3314.     if (value != NULL) {
  3315.         xmlChar *buffer;
  3316. xmlNodePtr tmp;
  3317. buffer = xmlEncodeEntitiesReentrant(node->doc, value);
  3318. prop->children = xmlStringGetNodeList(node->doc, buffer);
  3319. tmp = prop->children;
  3320. while (tmp != NULL) {
  3321.     tmp->parent = (xmlNodePtr) prop;
  3322.     if (tmp->next == NULL)
  3323. prop->last = tmp;
  3324.     tmp = tmp->next;
  3325. }
  3326. xmlFree(buffer);
  3327.     }
  3328.     return(prop);
  3329. }
  3330. prop = prop->next;
  3331.     }
  3332.     prop = xmlNewProp(node, name, value);
  3333.     return(prop);
  3334. }
  3335. /**
  3336.  * xmlNodeIsText:
  3337.  * @node:  the node
  3338.  * 
  3339.  * Is this node a Text node ?
  3340.  * Returns 1 yes, 0 no
  3341.  */
  3342. int
  3343. xmlNodeIsText(xmlNodePtr node) {
  3344.     if (node == NULL) return(0);
  3345.     if (node->type == XML_TEXT_NODE) return(1);
  3346.     return(0);
  3347. }
  3348. /**
  3349.  * xmlIsBlankNode:
  3350.  * @node:  the node
  3351.  * 
  3352.  * Is this node a Text node ?
  3353.  * Returns 1 yes, 0 no
  3354.  */
  3355. int
  3356. xmlIsBlankNode(xmlNodePtr node) {
  3357.     xmlChar *cur;
  3358.     if (node == NULL) return(0);
  3359.     if (node->type != XML_TEXT_NODE) return(0);
  3360.     if (node->content == NULL) return(0);
  3361.     cur = node->content;
  3362.     while (*cur != 0) {
  3363. if (!IS_BLANK(*cur)) return(0);
  3364. cur++;
  3365.     }
  3366.     return(1);
  3367. }
  3368. /**
  3369.  * xmlTextConcat:
  3370.  * @node:  the node
  3371.  * @content:  the content
  3372.  * @len:  @content lenght
  3373.  * 
  3374.  * Concat the given string at the end of the existing node content
  3375.  */
  3376. void
  3377. xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
  3378.     if (node == NULL) return;
  3379.     if ((node->type != XML_TEXT_NODE) &&
  3380.         (node->type != XML_CDATA_SECTION_NODE)) {
  3381. #ifdef DEBUG_TREE
  3382. fprintf(stderr, "xmlTextConcat: node is not text nor cdatan");
  3383. #endif
  3384.         return;
  3385.     }
  3386. #ifndef XML_USE_BUFFER_CONTENT
  3387.     node->content = xmlStrncat(node->content, content, len);
  3388. #else
  3389.     xmlBufferAdd(node->content, content, len);
  3390. #endif
  3391. }
  3392. /************************************************************************
  3393.  * *
  3394.  * Output : to a FILE or in memory *
  3395.  * *
  3396.  ************************************************************************/
  3397. #define BASE_BUFFER_SIZE 4000
  3398. /**
  3399.  * xmlBufferCreate:
  3400.  *
  3401.  * routine to create an XML buffer.
  3402.  * returns the new structure.
  3403.  */
  3404. xmlBufferPtr
  3405. xmlBufferCreate(void) {
  3406.     xmlBufferPtr ret;
  3407.     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
  3408.     if (ret == NULL) {
  3409. fprintf(stderr, "xmlBufferCreate : out of memory!n");
  3410.         return(NULL);
  3411.     }
  3412.     ret->use = 0;
  3413.     ret->size = BASE_BUFFER_SIZE;
  3414.     ret->alloc = xmlBufferAllocScheme;
  3415.     ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
  3416.     if (ret->content == NULL) {
  3417. fprintf(stderr, "xmlBufferCreate : out of memory!n");
  3418. xmlFree(ret);
  3419.         return(NULL);
  3420.     }
  3421.     ret->content[0] = 0;
  3422.     return(ret);
  3423. }
  3424. /**
  3425.  * xmlBufferCreateSize:
  3426.  * @size: initial size of buffer
  3427.  *
  3428.  * routine to create an XML buffer.
  3429.  * returns the new structure.
  3430.  */
  3431. xmlBufferPtr
  3432. xmlBufferCreateSize(size_t size) {
  3433.     xmlBufferPtr ret;
  3434.     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
  3435.     if (ret == NULL) {
  3436.         fprintf(stderr, "xmlBufferCreate : out of memory!n");
  3437.         return(NULL);
  3438.     }
  3439.     ret->use = 0;
  3440.     ret->alloc = xmlBufferAllocScheme;
  3441.     ret->size = (size ? size+2 : 0);         /* +1 for ending null */
  3442.     if (ret->size){
  3443.         ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
  3444.         if (ret->content == NULL) {
  3445.             fprintf(stderr, "xmlBufferCreate : out of memory!n");
  3446.             xmlFree(ret);
  3447.             return(NULL);
  3448.         }
  3449.         ret->content[0] = 0;
  3450.     } else
  3451. ret->content = NULL;
  3452.     return(ret);
  3453. }
  3454. /**
  3455.  * xmlBufferAllocationScheme:
  3456.  * @buf:  the buffer to free
  3457.  * @scheme:  allocation scheme to use
  3458.  *
  3459.  * Sets the allocation scheme for this buffer
  3460.  */
  3461. void
  3462. xmlBufferSetAllocationScheme(xmlBufferPtr buf, 
  3463.                              xmlBufferAllocationScheme scheme) {
  3464.     if (buf == NULL) {
  3465. #ifdef DEBUG_BUFFER
  3466.         fprintf(stderr, "xmlBufferSetAllocationScheme: buf == NULLn");
  3467. #endif
  3468.         return;
  3469.     }
  3470.     buf->alloc = scheme;
  3471. }
  3472. /**
  3473.  * xmlBufferFree:
  3474.  * @buf:  the buffer to free
  3475.  *
  3476.  * Frees an XML buffer.
  3477.  */
  3478. void
  3479. xmlBufferFree(xmlBufferPtr buf) {
  3480.     if (buf == NULL) {
  3481. #ifdef DEBUG_BUFFER
  3482.         fprintf(stderr, "xmlBufferFree: buf == NULLn");
  3483. #endif
  3484. return;
  3485.     }
  3486.     if (buf->content != NULL) {
  3487. #ifndef XML_USE_BUFFER_CONTENT
  3488.         memset(buf->content, -1, BASE_BUFFER_SIZE);
  3489. #else
  3490.         memset(buf->content, -1, buf->size);
  3491. #endif
  3492.         xmlFree(buf->content);
  3493.     }
  3494.     memset(buf, -1, sizeof(xmlBuffer));
  3495.     xmlFree(buf);
  3496. }
  3497. /**
  3498.  * xmlBufferEmpty:
  3499.  * @buf:  the buffer
  3500.  *
  3501.  * empty a buffer.
  3502.  */
  3503. void
  3504. xmlBufferEmpty(xmlBufferPtr buf) {
  3505.     buf->use = 0;
  3506.     memset(buf->content, -1, buf->size);/* just for debug */
  3507. }
  3508. /**
  3509.  * xmlBufferShrink:
  3510.  * @buf:  the buffer to dump
  3511.  * @len:  the number of xmlChar to remove
  3512.  *
  3513.  * Remove the beginning of an XML buffer.
  3514.  *
  3515.  * Returns the number of xmlChar removed, or -1 in case of failure.
  3516.  */
  3517. int
  3518. xmlBufferShrink(xmlBufferPtr buf, int len) {
  3519.     if (len == 0) return(0);
  3520.     if (len > buf->use) return(-1);
  3521.     buf->use -= len;
  3522.     memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
  3523.     buf->content[buf->use] = 0;
  3524.     return(len);
  3525. }
  3526. /**
  3527.  * xmlBufferDump:
  3528.  * @file:  the file output
  3529.  * @buf:  the buffer to dump
  3530.  *
  3531.  * Dumps an XML buffer to  a FILE *.
  3532.  * Returns the number of xmlChar written
  3533.  */
  3534. int
  3535. xmlBufferDump(FILE *file, xmlBufferPtr buf) {
  3536.     int ret;
  3537.     if (buf == NULL) {
  3538. #ifdef DEBUG_BUFFER
  3539.         fprintf(stderr, "xmlBufferDump: buf == NULLn");
  3540. #endif
  3541. return(0);
  3542.     }
  3543.     if (buf->content == NULL) {
  3544. #ifdef DEBUG_BUFFER
  3545.         fprintf(stderr, "xmlBufferDump: buf->content == NULLn");
  3546. #endif
  3547. return(0);
  3548.     }
  3549.     if (file == NULL) file = stdout;
  3550.     ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
  3551.     return(ret);
  3552. }
  3553. /**
  3554.  * xmlBufferContent:
  3555.  * @buf:  the buffer to resize
  3556.  *
  3557.  * Returns the internal content
  3558.  */
  3559. const xmlChar* 
  3560. xmlBufferContent(const xmlBufferPtr buf)
  3561. {
  3562.     if(!buf)
  3563.         return NULL;
  3564.     return buf->content;
  3565. }
  3566. /**
  3567.  * xmlBufferLength:
  3568.  * @buf:  the buffer 
  3569.  *
  3570.  * Returns the length of data in the internal content
  3571.  */
  3572. int
  3573. xmlBufferLength(const xmlBufferPtr buf)
  3574. {
  3575.     if(!buf)
  3576.         return 0;
  3577.     return buf->use;
  3578. }
  3579. /**
  3580.  * xmlBufferResize:
  3581.  * @buf:  the buffer to resize
  3582.  * @len:  the desired size
  3583.  *
  3584.  * Resize a buffer to accomodate minimum size of <len>.
  3585.  *
  3586.  * Returns  0 in case of problems, 1 otherwise
  3587.  */
  3588. int
  3589. xmlBufferResize(xmlBufferPtr buf, int size)
  3590. {
  3591.     int newSize = (buf->size ? buf->size*2 : size);/*take care of empty case*/
  3592.     xmlChar* rebuf = NULL;
  3593.     /* Don't resize if we don't have to */
  3594.     if(size < buf->size)
  3595.         return 1;
  3596.     /* figure out new size */
  3597.     switch(buf->alloc){
  3598.     case XML_BUFFER_ALLOC_DOUBLEIT:
  3599.         while(size > newSize) newSize *= 2;
  3600.         break;
  3601.     case XML_BUFFER_ALLOC_EXACT:
  3602.         newSize = size+10;
  3603.         break;
  3604.     default:
  3605.         newSize = size+10;
  3606.         break;
  3607.     }
  3608.     if (buf->content == NULL)
  3609. rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
  3610.     else
  3611. rebuf = (xmlChar *) xmlRealloc(buf->content, 
  3612.        newSize * sizeof(xmlChar));
  3613.     if (rebuf == NULL) {
  3614.         fprintf(stderr, "xmlBufferAdd : out of memory!n");
  3615.         return 0;
  3616.     }
  3617.     buf->content = rebuf;
  3618.     buf->size = newSize;
  3619.     return 1;
  3620. }
  3621. /**
  3622.  * xmlBufferAdd:
  3623.  * @buf:  the buffer to dump
  3624.  * @str:  the xmlChar string
  3625.  * @len:  the number of xmlChar to add
  3626.  *
  3627.  * Add a string range to an XML buffer. if len == -1, the lenght of
  3628.  * str is recomputed.
  3629.  */
  3630. void
  3631. xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
  3632.     int needSize;
  3633.     if (str == NULL) {
  3634. #ifdef DEBUG_BUFFER
  3635.         fprintf(stderr, "xmlBufferAdd: str == NULLn");
  3636. #endif
  3637. return;
  3638.     }
  3639.     if (len < -1) {
  3640. #ifdef DEBUG_BUFFER
  3641.         fprintf(stderr, "xmlBufferAdd: len < 0n");
  3642. #endif
  3643. return;
  3644.     }
  3645.     if (len == 0) return;
  3646.     if (len < 0)
  3647.         len = xmlStrlen(str);
  3648.     if (len <= 0) return;
  3649.     needSize = buf->use + len + 2;
  3650.     if(needSize > buf->size){
  3651.         if(!xmlBufferResize(buf, needSize)){
  3652.             fprintf(stderr, "xmlBufferAdd : out of memory!n");
  3653.             return;
  3654.         }
  3655.     }
  3656.     memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
  3657.     buf->use += len;
  3658.     buf->content[buf->use] = 0;
  3659. }
  3660. /**
  3661.  * xmlBufferCat:
  3662.  * @buf:  the buffer to dump
  3663.  * @str:  the xmlChar string
  3664.  *
  3665.  * Append a zero terminated string to an XML buffer.
  3666.  */
  3667. void
  3668. xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
  3669.     if (str != NULL)
  3670. xmlBufferAdd(buf, str, -1);
  3671. }
  3672. /**
  3673.  * xmlBufferCCat:
  3674.  * @buf:  the buffer to dump
  3675.  * @str:  the C char string
  3676.  *
  3677.  * Append a zero terminated C string to an XML buffer.
  3678.  */
  3679. void
  3680. xmlBufferCCat(xmlBufferPtr buf, const char *str) {
  3681.     const char *cur;
  3682.     if (str == NULL) {
  3683. #ifdef DEBUG_BUFFER
  3684.         fprintf(stderr, "xmlBufferAdd: str == NULLn");
  3685. #endif
  3686. return;
  3687.     }
  3688.     for (cur = str;*cur != 0;cur++) {
  3689.         if (buf->use  + 10 >= buf->size) {
  3690.             if(!xmlBufferResize(buf, buf->use+10)){
  3691.                 fprintf(stderr, "xmlBufferCCat : out of memory!n");
  3692.                 return;
  3693.             }
  3694.         }
  3695.         buf->content[buf->use++] = *cur;
  3696.     }
  3697. }
  3698. /**
  3699.  * xmlBufferWriteCHAR:
  3700.  * @buf:  the XML buffer
  3701.  * @string:  the string to add
  3702.  *
  3703.  * routine which manage and grows an output buffer. This one add
  3704.  * xmlChars at the end of the buffer.
  3705.  */
  3706. void
  3707. xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
  3708.     xmlBufferCat(buf, string);
  3709. }
  3710. /**
  3711.  * xmlBufferWriteChar:
  3712.  * @buf:  the XML buffer output
  3713.  * @string:  the string to add
  3714.  *
  3715.  * routine which manage and grows an output buffer. This one add
  3716.  * C chars at the end of the array.
  3717.  */
  3718. void
  3719. xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
  3720.     xmlBufferCCat(buf, string);
  3721. }
  3722. /**
  3723.  * xmlBufferWriteQuotedString:
  3724.  * @buf:  the XML buffer output
  3725.  * @string:  the string to add
  3726.  *
  3727.  * routine which manage and grows an output buffer. This one writes
  3728.  * a quoted or double quoted xmlChar string, checking first if it holds
  3729.  * quote or double-quotes internally
  3730.  */
  3731. void
  3732. xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
  3733.     if (xmlStrchr(string, '"')) {
  3734.         if (xmlStrchr(string, ''')) {
  3735. #ifdef DEBUG_BUFFER
  3736.     fprintf(stderr,
  3737.  "xmlBufferWriteQuotedString: string contains quote and double-quotes !n");
  3738. #endif
  3739. }
  3740.         xmlBufferCCat(buf, "'");
  3741.         xmlBufferCat(buf, string);
  3742.         xmlBufferCCat(buf, "'");
  3743.     } else {
  3744.         xmlBufferCCat(buf, """);
  3745.         xmlBufferCat(buf, string);
  3746.         xmlBufferCCat(buf, """);
  3747.     }
  3748. }
  3749. static void
  3750. xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
  3751.             int format);
  3752. static void
  3753. xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
  3754.                 int format);
  3755. void
  3756. htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
  3757. /**
  3758.  * xmlGlobalNsDump:
  3759.  * @buf:  the XML buffer output
  3760.  * @cur:  a namespace
  3761.  *
  3762.  * Dump a global Namespace, this is the old version based on PIs.
  3763.  */
  3764. static void
  3765. xmlGlobalNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
  3766.     if (cur == NULL) {
  3767. #ifdef DEBUG_TREE
  3768.         fprintf(stderr, "xmlGlobalNsDump : Ns == NULLn");
  3769. #endif
  3770. return;
  3771.     }
  3772.     if (cur->type == XML_GLOBAL_NAMESPACE) {
  3773. xmlBufferWriteChar(buf, "<?namespace");
  3774. if (cur->href != NULL) {
  3775.     xmlBufferWriteChar(buf, " href=");
  3776.     xmlBufferWriteQuotedString(buf, cur->href);
  3777. }
  3778. if (cur->prefix != NULL) {
  3779.     xmlBufferWriteChar(buf, " AS=");
  3780.     xmlBufferWriteQuotedString(buf, cur->prefix);
  3781. }
  3782. xmlBufferWriteChar(buf, "?>n");
  3783.     }
  3784. }
  3785. /**
  3786.  * xmlGlobalNsListDump:
  3787.  * @buf:  the XML buffer output
  3788.  * @cur:  the first namespace
  3789.  *
  3790.  * Dump a list of global Namespace, this is the old version based on PIs.
  3791.  */
  3792. static void
  3793. xmlGlobalNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
  3794.     while (cur != NULL) {
  3795.         xmlGlobalNsDump(buf, cur);
  3796. cur = cur->next;
  3797.     }
  3798. }
  3799. /**
  3800.  * xmlNsDump:
  3801.  * @buf:  the XML buffer output
  3802.  * @cur:  a namespace
  3803.  *
  3804.  * Dump a local Namespace definition.
  3805.  * Should be called in the context of attributes dumps.
  3806.  */
  3807. static void
  3808. xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
  3809.     if (cur == NULL) {
  3810. #ifdef DEBUG_TREE
  3811.         fprintf(stderr, "xmlNsDump : Ns == NULLn");
  3812. #endif
  3813. return;
  3814.     }
  3815.     if (cur->type == XML_LOCAL_NAMESPACE) {
  3816.         /* Within the context of an element attributes */
  3817. if (cur->prefix != NULL) {
  3818.     xmlBufferWriteChar(buf, " xmlns:");
  3819.     xmlBufferWriteCHAR(buf, cur->prefix);
  3820. } else
  3821.     xmlBufferWriteChar(buf, " xmlns");
  3822. xmlBufferWriteChar(buf, "=");
  3823. xmlBufferWriteQuotedString(buf, cur->href);
  3824.     }
  3825. }
  3826. /**
  3827.  * xmlNsListDump:
  3828.  * @buf:  the XML buffer output
  3829.  * @cur:  the first namespace
  3830.  *
  3831.  * Dump a list of local Namespace definitions.
  3832.  * Should be called in the context of attributes dumps.
  3833.  */
  3834. static void
  3835. xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
  3836.     while (cur != NULL) {
  3837.         xmlNsDump(buf, cur);
  3838. cur = cur->next;
  3839.     }
  3840. }
  3841. /**
  3842.  * xmlDtdDump:
  3843.  * @buf:  the XML buffer output
  3844.  * @doc:  the document
  3845.  * 
  3846.  * Dump the XML document DTD, if any.
  3847.  */
  3848. static void
  3849. xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
  3850.     if (dtd == NULL) {
  3851. #ifdef DEBUG_TREE
  3852.         fprintf(stderr, "xmlDtdDump : no internal subsetn");
  3853. #endif
  3854. return;
  3855.     }
  3856.     xmlBufferWriteChar(buf, "<!DOCTYPE ");
  3857.     xmlBufferWriteCHAR(buf, dtd->name);
  3858.     if (dtd->ExternalID != NULL) {
  3859. xmlBufferWriteChar(buf, " PUBLIC ");
  3860. xmlBufferWriteQuotedString(buf, dtd->ExternalID);
  3861. xmlBufferWriteChar(buf, " ");
  3862. xmlBufferWriteQuotedString(buf, dtd->SystemID);
  3863.     }  else if (dtd->SystemID != NULL) {
  3864. xmlBufferWriteChar(buf, " SYSTEM ");
  3865. xmlBufferWriteQuotedString(buf, dtd->SystemID);
  3866.     }
  3867.     if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
  3868.         (dtd->attributes == NULL) && (dtd->notations == NULL)) {
  3869. xmlBufferWriteChar(buf, ">");
  3870. return;
  3871.     }
  3872.     xmlBufferWriteChar(buf, " [n");
  3873.     xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
  3874. #if 0
  3875.     if (dtd->entities != NULL)
  3876. xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
  3877.     if (dtd->notations != NULL)
  3878. xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
  3879.     if (dtd->elements != NULL)
  3880. xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
  3881.     if (dtd->attributes != NULL)
  3882. xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
  3883. #endif
  3884.     xmlBufferWriteChar(buf, "]>");
  3885. }
  3886. /**
  3887.  * xmlAttrDump:
  3888.  * @buf:  the XML buffer output
  3889.  * @doc:  the document
  3890.  * @cur:  the attribute pointer
  3891.  *
  3892.  * Dump an XML attribute
  3893.  */
  3894. static void
  3895. xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
  3896.     xmlChar *value;
  3897.     if (cur == NULL) {
  3898. #ifdef DEBUG_TREE
  3899.         fprintf(stderr, "xmlAttrDump : property == NULLn");
  3900. #endif
  3901. return;
  3902.     }
  3903.     xmlBufferWriteChar(buf, " ");
  3904.     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
  3905.         xmlBufferWriteCHAR(buf, cur->ns->prefix);
  3906. xmlBufferWriteChar(buf, ":");
  3907.     }
  3908.     xmlBufferWriteCHAR(buf, cur->name);
  3909.     value = xmlNodeListGetString(doc, cur->children, 0);
  3910.     if (value) {
  3911. xmlBufferWriteChar(buf, "=");
  3912. xmlBufferWriteQuotedString(buf, value);
  3913. xmlFree(value);
  3914.     } else  {
  3915. xmlBufferWriteChar(buf, "=""");
  3916.     }
  3917. }
  3918. /**
  3919.  * xmlAttrListDump:
  3920.  * @buf:  the XML buffer output
  3921.  * @doc:  the document
  3922.  * @cur:  the first attribute pointer
  3923.  *
  3924.  * Dump a list of XML attributes
  3925.  */
  3926. static void
  3927. xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
  3928.     if (cur == NULL) {
  3929. #ifdef DEBUG_TREE
  3930.         fprintf(stderr, "xmlAttrListDump : property == NULLn");
  3931. #endif
  3932. return;
  3933.     }
  3934.     while (cur != NULL) {
  3935.         xmlAttrDump(buf, doc, cur);
  3936. cur = cur->next;
  3937.     }
  3938. }
  3939. /**
  3940.  * xmlNodeListDump:
  3941.  * @buf:  the XML buffer output
  3942.  * @doc:  the document
  3943.  * @cur:  the first node
  3944.  * @level: the imbrication level for indenting
  3945.  * @format: is formatting allowed
  3946.  *
  3947.  * Dump an XML node list, recursive behaviour,children are printed too.
  3948.  */
  3949. static void
  3950. xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
  3951.                 int format) {
  3952.     int i;
  3953.     if (cur == NULL) {
  3954. #ifdef DEBUG_TREE
  3955.         fprintf(stderr, "xmlNodeListDump : node == NULLn");
  3956. #endif
  3957. return;
  3958.     }
  3959.     while (cur != NULL) {
  3960. if ((format) && (xmlIndentTreeOutput) &&
  3961.     (cur->type == XML_ELEMENT_NODE))
  3962.     for (i = 0;i < level;i++)
  3963. xmlBufferWriteChar(buf, "  ");
  3964.         xmlNodeDump(buf, doc, cur, level, format);
  3965. if (format) {
  3966.     xmlBufferWriteChar(buf, "n");
  3967. }
  3968. cur = cur->next;
  3969.     }
  3970. }
  3971. /**
  3972.  * xmlNodeDump:
  3973.  * @buf:  the XML buffer output
  3974.  * @doc:  the document
  3975.  * @cur:  the current node
  3976.  * @level: the imbrication level for indenting
  3977.  * @format: is formatting allowed
  3978.  *
  3979.  * Dump an XML node, recursive behaviour,children are printed too.
  3980.  */
  3981. static void
  3982. xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
  3983.             int format) {
  3984.     int i;
  3985.     xmlNodePtr tmp;
  3986.     if (cur == NULL) {
  3987. #ifdef DEBUG_TREE
  3988.         fprintf(stderr, "xmlNodeDump : node == NULLn");
  3989. #endif
  3990. return;
  3991.     }
  3992.     if (cur->type == XML_DTD_NODE) {
  3993.         xmlDtdDump(buf, (xmlDtdPtr) cur);
  3994. return;
  3995.     }
  3996.     if (cur->type == XML_ELEMENT_DECL) {
  3997.         xmlDumpElementDecl(buf, (xmlElementPtr) cur);
  3998. return;
  3999.     }
  4000.     if (cur->type == XML_ATTRIBUTE_DECL) {
  4001.         xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
  4002. return;
  4003.     }
  4004.     if (cur->type == XML_ENTITY_DECL) {
  4005.         xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
  4006. return;
  4007.     }
  4008.     if (cur->type == XML_TEXT_NODE) {
  4009. if (cur->content != NULL) {
  4010.             xmlChar *buffer;
  4011. #ifndef XML_USE_BUFFER_CONTENT
  4012.             buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
  4013. #else
  4014.     buffer = xmlEncodeEntitiesReentrant(doc, 
  4015.     xmlBufferContent(cur->content));
  4016. #endif
  4017.     if (buffer != NULL) {
  4018. xmlBufferWriteCHAR(buf, buffer);
  4019. xmlFree(buffer);
  4020.     }
  4021. }
  4022. return;
  4023.     }
  4024.     if (cur->type == XML_PI_NODE) {
  4025. if (cur->content != NULL) {
  4026.     xmlBufferWriteChar(buf, "<?");
  4027.     xmlBufferWriteCHAR(buf, cur->name);
  4028.     if (cur->content != NULL) {
  4029. xmlBufferWriteChar(buf, " ");
  4030. #ifndef XML_USE_BUFFER_CONTENT
  4031. xmlBufferWriteCHAR(buf, cur->content);
  4032. #else
  4033. xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
  4034. #endif
  4035.     }
  4036.     xmlBufferWriteChar(buf, "?>");
  4037. } else {
  4038.     xmlBufferWriteChar(buf, "<?");
  4039.     xmlBufferWriteCHAR(buf, cur->name);
  4040.     xmlBufferWriteChar(buf, "?>");
  4041. }
  4042. return;
  4043.     }
  4044.     if (cur->type == XML_COMMENT_NODE) {
  4045. if (cur->content != NULL) {
  4046.     xmlBufferWriteChar(buf, "<!--");
  4047. #ifndef XML_USE_BUFFER_CONTENT
  4048.     xmlBufferWriteCHAR(buf, cur->content);
  4049. #else
  4050.     xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
  4051. #endif
  4052.     xmlBufferWriteChar(buf, "-->");
  4053. }
  4054. return;
  4055.     }
  4056.     if (cur->type == XML_ENTITY_REF_NODE) {
  4057.         xmlBufferWriteChar(buf, "&");
  4058. xmlBufferWriteCHAR(buf, cur->name);
  4059.         xmlBufferWriteChar(buf, ";");
  4060. return;
  4061.     }
  4062.     if (cur->type == XML_CDATA_SECTION_NODE) {
  4063.         xmlBufferWriteChar(buf, "<![CDATA[");
  4064. if (cur->content != NULL)
  4065. #ifndef XML_USE_BUFFER_CONTENT
  4066.     xmlBufferWriteCHAR(buf, cur->content);
  4067. #else
  4068.     xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
  4069. #endif
  4070.         xmlBufferWriteChar(buf, "]]>");
  4071. return;
  4072.     }
  4073.     if (format == 1) {
  4074. tmp = cur->children;
  4075. while (tmp != NULL) {
  4076.     if ((tmp->type == XML_TEXT_NODE) || 
  4077. (tmp->type == XML_ENTITY_REF_NODE)) {
  4078. format = 0;
  4079. break;
  4080.     }
  4081.     tmp = tmp->next;
  4082. }
  4083.     }
  4084.     xmlBufferWriteChar(buf, "<");
  4085.     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
  4086.         xmlBufferWriteCHAR(buf, cur->ns->prefix);
  4087. xmlBufferWriteChar(buf, ":");
  4088.     }
  4089.     xmlBufferWriteCHAR(buf, cur->name);
  4090.     if (cur->nsDef)
  4091.         xmlNsListDump(buf, cur->nsDef);
  4092.     if (cur->properties != NULL)
  4093.         xmlAttrListDump(buf, doc, cur->properties);
  4094.     if ((cur->content == NULL) && (cur->children == NULL) &&
  4095. (!xmlSaveNoEmptyTags)) {
  4096.         xmlBufferWriteChar(buf, "/>");
  4097. return;
  4098.     }
  4099.     xmlBufferWriteChar(buf, ">");
  4100.     if (cur->content != NULL) {
  4101. xmlChar *buffer;
  4102. #ifndef XML_USE_BUFFER_CONTENT
  4103. buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
  4104. #else
  4105. buffer = xmlEncodeEntitiesReentrant(doc, 
  4106.                             xmlBufferContent(cur->content));
  4107. #endif
  4108. if (buffer != NULL) {
  4109.     xmlBufferWriteCHAR(buf, buffer);
  4110.     xmlFree(buffer);
  4111. }
  4112.     }
  4113.     if (cur->children != NULL) {
  4114. if (format) xmlBufferWriteChar(buf, "n");
  4115. xmlNodeListDump(buf, doc, cur->children,
  4116.         (level >= 0?level+1:-1), format);
  4117. if ((xmlIndentTreeOutput) && (format))
  4118.     for (i = 0;i < level;i++)
  4119. xmlBufferWriteChar(buf, "  ");
  4120.     }
  4121.     xmlBufferWriteChar(buf, "</");
  4122.     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
  4123.         xmlBufferWriteCHAR(buf, cur->ns->prefix);
  4124. xmlBufferWriteChar(buf, ":");
  4125.     }
  4126.     xmlBufferWriteCHAR(buf, cur->name);
  4127.     xmlBufferWriteChar(buf, ">");
  4128. }
  4129. /**
  4130.  * xmlElemDump:
  4131.  * @buf:  the XML buffer output
  4132.  * @doc:  the document
  4133.  * @cur:  the current node
  4134.  *
  4135.  * Dump an XML/HTML node, recursive behaviour,children are printed too.
  4136.  */
  4137. void
  4138. xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
  4139.     xmlBufferPtr buf;
  4140.     if (cur == NULL) {
  4141. #ifdef DEBUG_TREE
  4142.         fprintf(stderr, "xmlElemDump : cur == NULLn");
  4143. #endif
  4144. return;
  4145.     }
  4146.     if (doc == NULL) {
  4147. #ifdef DEBUG_TREE
  4148.         fprintf(stderr, "xmlElemDump : doc == NULLn");
  4149. #endif
  4150.     }
  4151.     buf = xmlBufferCreate();
  4152.     if (buf == NULL) return;
  4153.     if ((doc != NULL) && 
  4154.         (doc->type == XML_HTML_DOCUMENT_NODE)) {
  4155. #ifdef LIBXML_HTML_ENABLED
  4156.         htmlNodeDump(buf, doc, cur);
  4157. #else
  4158. printf("HTML support not compiled inn");
  4159. #endif /* LIBXML_HTML_ENABLED */
  4160.     } else
  4161.         xmlNodeDump(buf, doc, cur, 0, 1);
  4162.     xmlBufferDump(f, buf);
  4163.     xmlBufferFree(buf);
  4164. }
  4165. /**
  4166.  * xmlDocContentDump:
  4167.  * @buf:  the XML buffer output
  4168.  * @cur:  the document
  4169.  *
  4170.  * Dump an XML document.
  4171.  */
  4172. static void
  4173. xmlDocContentDump(xmlBufferPtr buf, xmlDocPtr cur) {
  4174.     xmlBufferWriteChar(buf, "<?xml version=");
  4175.     if (cur->version != NULL) 
  4176. xmlBufferWriteQuotedString(buf, cur->version);
  4177.     else
  4178. xmlBufferWriteChar(buf, ""1.0"");
  4179.     if (cur->encoding != NULL) {
  4180.         xmlBufferWriteChar(buf, " encoding=");
  4181. xmlBufferWriteQuotedString(buf, cur->encoding);
  4182.     }
  4183.     switch (cur->standalone) {
  4184.         case 0:
  4185.     xmlBufferWriteChar(buf, " standalone="no"");
  4186.     break;
  4187.         case 1:
  4188.     xmlBufferWriteChar(buf, " standalone="yes"");
  4189.     break;
  4190.     }
  4191.     xmlBufferWriteChar(buf, "?>n");
  4192.     if (cur->children != NULL) {
  4193.         xmlNodePtr child = cur->children;
  4194. /* global namespace definitions, the old way */
  4195. if (oldXMLWDcompatibility)
  4196.     xmlGlobalNsListDump(buf, cur->oldNs);
  4197. else 
  4198.     xmlUpgradeOldNs(cur);
  4199. while (child != NULL) {
  4200.     xmlNodeDump(buf, cur, child, 0, 1);
  4201.     xmlBufferWriteChar(buf, "n");
  4202.     child = child->next;
  4203. }
  4204.     }
  4205. }
  4206. /**
  4207.  * xmlDocDumpMemory:
  4208.  * @cur:  the document
  4209.  * @mem:  OUT: the memory pointer
  4210.  * @size:  OUT: the memory lenght
  4211.  *
  4212.  * Dump an XML document in memory and return the xmlChar * and it's size.
  4213.  * It's up to the caller to free the memory.
  4214.  */
  4215. void
  4216. xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
  4217.     xmlBufferPtr buf;
  4218.     if (cur == NULL) {
  4219. #ifdef DEBUG_TREE
  4220.         fprintf(stderr, "xmlDocDumpMemory : document == NULLn");
  4221. #endif
  4222. *mem = NULL;
  4223. *size = 0;
  4224. return;
  4225.     }
  4226.     buf = xmlBufferCreate();
  4227.     if (buf == NULL) {
  4228. *mem = NULL;
  4229. *size = 0;
  4230. return;
  4231.     }
  4232.     xmlDocContentDump(buf, cur);
  4233.     *mem = xmlStrndup(buf->content, buf->use);
  4234.     *size = buf->use;
  4235.     xmlBufferFree(buf);
  4236. }
  4237. /**
  4238.  * xmlGetDocCompressMode:
  4239.  * @doc:  the document
  4240.  *
  4241.  * get the compression ratio for a document, ZLIB based
  4242.  * Returns 0 (uncompressed) to 9 (max compression)
  4243.  */
  4244. int
  4245. xmlGetDocCompressMode (xmlDocPtr doc) {
  4246.     if (doc == NULL) return(-1);
  4247.     return(doc->compression);
  4248. }
  4249. /**
  4250.  * xmlSetDocCompressMode:
  4251.  * @doc:  the document
  4252.  * @mode:  the compression ratio
  4253.  *
  4254.  * set the compression ratio for a document, ZLIB based
  4255.  * Correct values: 0 (uncompressed) to 9 (max compression)
  4256.  */
  4257. void
  4258. xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
  4259.     if (doc == NULL) return;
  4260.     if (mode < 0) doc->compression = 0;
  4261.     else if (mode > 9) doc->compression = 9;
  4262.     else doc->compression = mode;
  4263. }
  4264. /**
  4265.  * xmlGetCompressMode:
  4266.  *
  4267.  * get the default compression mode used, ZLIB based.
  4268.  * Returns 0 (uncompressed) to 9 (max compression)
  4269.  */
  4270. int
  4271.  xmlGetCompressMode(void) {
  4272.     return(xmlCompressMode);
  4273. }
  4274. /**
  4275.  * xmlSetCompressMode:
  4276.  * @mode:  the compression ratio
  4277.  *
  4278.  * set the default compression mode used, ZLIB based
  4279.  * Correct values: 0 (uncompressed) to 9 (max compression)
  4280.  */
  4281. void
  4282. xmlSetCompressMode(int mode) {
  4283.     if (mode < 0) xmlCompressMode = 0;
  4284.     else if (mode > 9) xmlCompressMode = 9;
  4285.     else xmlCompressMode = mode;
  4286. }
  4287. /**
  4288.  * xmlDocDump:
  4289.  * @f:  the FILE*
  4290.  * @cur:  the document
  4291.  *
  4292.  * Dump an XML document to an open FILE.
  4293.  */
  4294. void
  4295. xmlDocDump(FILE *f, xmlDocPtr cur) {
  4296.     xmlBufferPtr buf;
  4297.     if (cur == NULL) {
  4298. #ifdef DEBUG_TREE
  4299.         fprintf(stderr, "xmlDocDump : document == NULLn");
  4300. #endif
  4301. return;
  4302.     }
  4303.     buf = xmlBufferCreate();
  4304.     if (buf == NULL) return;
  4305.     xmlDocContentDump(buf, cur);
  4306.     xmlBufferDump(f, buf);
  4307.     xmlBufferFree(buf);
  4308. }
  4309. /**
  4310.  * xmlSaveFile:
  4311.  * @filename:  the filename
  4312.  * @cur:  the document
  4313.  *
  4314.  * Dump an XML document to a file. Will use compression if
  4315.  * compiled in and enabled. If @filename is "-" the stdout file is
  4316.  * used.
  4317.  * returns: the number of file written or -1 in case of failure.
  4318.  */
  4319. int
  4320. xmlSaveFile(const char *filename, xmlDocPtr cur) {
  4321.     xmlBufferPtr buf;
  4322. #ifdef HAVE_ZLIB_H
  4323.     gzFile zoutput = NULL;
  4324.     char mode[15];
  4325. #endif
  4326.     FILE *output = NULL;
  4327.     int ret;
  4328.     /* 
  4329.      * save the content to a temp buffer.
  4330.      */
  4331.     buf = xmlBufferCreate();
  4332.     if (buf == NULL) return(0);
  4333.     xmlDocContentDump(buf, cur);
  4334. #ifdef HAVE_ZLIB_H
  4335.     if (cur->compression < 0) cur->compression = xmlCompressMode;
  4336.     if ((cur->compression > 0) && (cur->compression <= 9)) {
  4337.         sprintf(mode, "w%d", cur->compression);
  4338. if (!strcmp(filename, "-")) 
  4339.     zoutput = gzdopen(1, mode);
  4340. else
  4341.     zoutput = gzopen(filename, mode);
  4342.     }
  4343.     if (zoutput == NULL) {
  4344. #endif
  4345.         output = fopen(filename, "w");
  4346. if (output == NULL) {
  4347.     xmlBufferFree(buf);
  4348.     return(-1);
  4349. }
  4350. #ifdef HAVE_ZLIB_H
  4351.     }
  4352.     if (zoutput != NULL) {
  4353.         ret = gzwrite(zoutput, buf->content, sizeof(xmlChar) * buf->use);
  4354. gzclose(zoutput);
  4355.     } else {
  4356. #endif
  4357.         ret = xmlBufferDump(output, buf);
  4358. fclose(output);
  4359. #ifdef HAVE_ZLIB_H
  4360.     }
  4361. #endif
  4362.     xmlBufferFree(buf);
  4363.     return(ret * sizeof(xmlChar));
  4364. }