File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xmlsave.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:22:18 2013 UTC (10 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_8_0p0, v2_8_0, HEAD
2.8.0

    1: /*
    2:  * xmlsave.c: Implemetation of the document serializer
    3:  *
    4:  * See Copyright for the status of this software.
    5:  *
    6:  * daniel@veillard.com
    7:  */
    8: 
    9: #define IN_LIBXML
   10: #include "libxml.h"
   11: 
   12: #include <string.h>
   13: #include <libxml/xmlmemory.h>
   14: #include <libxml/parserInternals.h>
   15: #include <libxml/tree.h>
   16: #include <libxml/xmlsave.h>
   17: 
   18: #define MAX_INDENT 60
   19: 
   20: #include <libxml/HTMLtree.h>
   21: 
   22: /************************************************************************
   23:  *									*
   24:  *			XHTML detection					*
   25:  *									*
   26:  ************************************************************************/
   27: #define XHTML_STRICT_PUBLIC_ID BAD_CAST \
   28:    "-//W3C//DTD XHTML 1.0 Strict//EN"
   29: #define XHTML_STRICT_SYSTEM_ID BAD_CAST \
   30:    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
   31: #define XHTML_FRAME_PUBLIC_ID BAD_CAST \
   32:    "-//W3C//DTD XHTML 1.0 Frameset//EN"
   33: #define XHTML_FRAME_SYSTEM_ID BAD_CAST \
   34:    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
   35: #define XHTML_TRANS_PUBLIC_ID BAD_CAST \
   36:    "-//W3C//DTD XHTML 1.0 Transitional//EN"
   37: #define XHTML_TRANS_SYSTEM_ID BAD_CAST \
   38:    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
   39: 
   40: #define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
   41: /**
   42:  * xmlIsXHTML:
   43:  * @systemID:  the system identifier
   44:  * @publicID:  the public identifier
   45:  *
   46:  * Try to find if the document correspond to an XHTML DTD
   47:  *
   48:  * Returns 1 if true, 0 if not and -1 in case of error
   49:  */
   50: int
   51: xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
   52:     if ((systemID == NULL) && (publicID == NULL))
   53: 	return(-1);
   54:     if (publicID != NULL) {
   55: 	if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
   56: 	if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
   57: 	if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
   58:     }
   59:     if (systemID != NULL) {
   60: 	if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
   61: 	if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
   62: 	if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
   63:     }
   64:     return(0);
   65: }
   66: 
   67: #ifdef LIBXML_OUTPUT_ENABLED
   68: 
   69: #define TODO 								\
   70:     xmlGenericError(xmlGenericErrorContext,				\
   71: 	    "Unimplemented block at %s:%d\n",				\
   72:             __FILE__, __LINE__);
   73: 
   74: struct _xmlSaveCtxt {
   75:     void *_private;
   76:     int type;
   77:     int fd;
   78:     const xmlChar *filename;
   79:     const xmlChar *encoding;
   80:     xmlCharEncodingHandlerPtr handler;
   81:     xmlOutputBufferPtr buf;
   82:     xmlDocPtr doc;
   83:     int options;
   84:     int level;
   85:     int format;
   86:     char indent[MAX_INDENT + 1];	/* array for indenting output */
   87:     int indent_nr;
   88:     int indent_size;
   89:     xmlCharEncodingOutputFunc escape;	/* used for element content */
   90:     xmlCharEncodingOutputFunc escapeAttr;/* used for attribute content */
   91: };
   92: 
   93: /************************************************************************
   94:  *									*
   95:  * 			Output error handlers				*
   96:  *									*
   97:  ************************************************************************/
   98: /**
   99:  * xmlSaveErrMemory:
  100:  * @extra:  extra informations
  101:  *
  102:  * Handle an out of memory condition
  103:  */
  104: static void
  105: xmlSaveErrMemory(const char *extra)
  106: {
  107:     __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
  108: }
  109: 
  110: /**
  111:  * xmlSaveErr:
  112:  * @code:  the error number
  113:  * @node:  the location of the error.
  114:  * @extra:  extra informations
  115:  *
  116:  * Handle an out of memory condition
  117:  */
  118: static void
  119: xmlSaveErr(int code, xmlNodePtr node, const char *extra)
  120: {
  121:     const char *msg = NULL;
  122: 
  123:     switch(code) {
  124:         case XML_SAVE_NOT_UTF8:
  125: 	    msg = "string is not in UTF-8\n";
  126: 	    break;
  127: 	case XML_SAVE_CHAR_INVALID:
  128: 	    msg = "invalid character value\n";
  129: 	    break;
  130: 	case XML_SAVE_UNKNOWN_ENCODING:
  131: 	    msg = "unknown encoding %s\n";
  132: 	    break;
  133: 	case XML_SAVE_NO_DOCTYPE:
  134: 	    msg = "document has no DOCTYPE\n";
  135: 	    break;
  136: 	default:
  137: 	    msg = "unexpected error number\n";
  138:     }
  139:     __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
  140: }
  141: 
  142: /************************************************************************
  143:  *									*
  144:  *			Special escaping routines			*
  145:  *									*
  146:  ************************************************************************/
  147: static unsigned char *
  148: xmlSerializeHexCharRef(unsigned char *out, int val) {
  149:     unsigned char *ptr;
  150: 
  151:     *out++ = '&';
  152:     *out++ = '#';
  153:     *out++ = 'x';
  154:     if (val < 0x10) ptr = out;
  155:     else if (val < 0x100) ptr = out + 1;
  156:     else if (val < 0x1000) ptr = out + 2;
  157:     else if (val < 0x10000) ptr = out + 3;
  158:     else if (val < 0x100000) ptr = out + 4;
  159:     else ptr = out + 5;
  160:     out = ptr + 1;
  161:     while (val > 0) {
  162: 	switch (val & 0xF) {
  163: 	    case 0: *ptr-- = '0'; break;
  164: 	    case 1: *ptr-- = '1'; break;
  165: 	    case 2: *ptr-- = '2'; break;
  166: 	    case 3: *ptr-- = '3'; break;
  167: 	    case 4: *ptr-- = '4'; break;
  168: 	    case 5: *ptr-- = '5'; break;
  169: 	    case 6: *ptr-- = '6'; break;
  170: 	    case 7: *ptr-- = '7'; break;
  171: 	    case 8: *ptr-- = '8'; break;
  172: 	    case 9: *ptr-- = '9'; break;
  173: 	    case 0xA: *ptr-- = 'A'; break;
  174: 	    case 0xB: *ptr-- = 'B'; break;
  175: 	    case 0xC: *ptr-- = 'C'; break;
  176: 	    case 0xD: *ptr-- = 'D'; break;
  177: 	    case 0xE: *ptr-- = 'E'; break;
  178: 	    case 0xF: *ptr-- = 'F'; break;
  179: 	    default: *ptr-- = '0'; break;
  180: 	}
  181: 	val >>= 4;
  182:     }
  183:     *out++ = ';';
  184:     *out = 0;
  185:     return(out);
  186: }
  187: 
  188: /**
  189:  * xmlEscapeEntities:
  190:  * @out:  a pointer to an array of bytes to store the result
  191:  * @outlen:  the length of @out
  192:  * @in:  a pointer to an array of unescaped UTF-8 bytes
  193:  * @inlen:  the length of @in
  194:  *
  195:  * Take a block of UTF-8 chars in and escape them. Used when there is no
  196:  * encoding specified.
  197:  *
  198:  * Returns 0 if success, or -1 otherwise
  199:  * The value of @inlen after return is the number of octets consumed
  200:  *     if the return value is positive, else unpredictable.
  201:  * The value of @outlen after return is the number of octets consumed.
  202:  */
  203: static int
  204: xmlEscapeEntities(unsigned char* out, int *outlen,
  205:                  const xmlChar* in, int *inlen) {
  206:     unsigned char* outstart = out;
  207:     const unsigned char* base = in;
  208:     unsigned char* outend = out + *outlen;
  209:     const unsigned char* inend;
  210:     int val;
  211: 
  212:     inend = in + (*inlen);
  213:     
  214:     while ((in < inend) && (out < outend)) {
  215:     	if (*in == '<') {
  216: 	    if (outend - out < 4) break;
  217: 	    *out++ = '&';
  218: 	    *out++ = 'l';
  219: 	    *out++ = 't';
  220: 	    *out++ = ';';
  221: 	    in++;
  222: 	    continue;
  223: 	} else if (*in == '>') {
  224: 	    if (outend - out < 4) break;
  225: 	    *out++ = '&';
  226: 	    *out++ = 'g';
  227: 	    *out++ = 't';
  228: 	    *out++ = ';';
  229: 	    in++;
  230: 	    continue;
  231: 	} else if (*in == '&') {
  232: 	    if (outend - out < 5) break;
  233: 	    *out++ = '&';
  234: 	    *out++ = 'a';
  235: 	    *out++ = 'm';
  236: 	    *out++ = 'p';
  237: 	    *out++ = ';';
  238: 	    in++;
  239: 	    continue;
  240: 	} else if (((*in >= 0x20) && (*in < 0x80)) ||
  241: 	           (*in == '\n') || (*in == '\t')) {
  242: 	    /*
  243: 	     * default case, just copy !
  244: 	     */
  245: 	    *out++ = *in++;
  246: 	    continue;
  247: 	} else if (*in >= 0x80) {
  248: 	    /*
  249: 	     * We assume we have UTF-8 input.
  250: 	     */
  251: 	    if (outend - out < 11) break;
  252: 
  253: 	    if (*in < 0xC0) {
  254: 		xmlSaveErr(XML_SAVE_NOT_UTF8, NULL, NULL);
  255: 		in++;
  256: 		goto error;
  257: 	    } else if (*in < 0xE0) {
  258: 		if (inend - in < 2) break;
  259: 		val = (in[0]) & 0x1F;
  260: 		val <<= 6;
  261: 		val |= (in[1]) & 0x3F;
  262: 		in += 2;
  263: 	    } else if (*in < 0xF0) {
  264: 		if (inend - in < 3) break;
  265: 		val = (in[0]) & 0x0F;
  266: 		val <<= 6;
  267: 		val |= (in[1]) & 0x3F;
  268: 		val <<= 6;
  269: 		val |= (in[2]) & 0x3F;
  270: 		in += 3;
  271: 	    } else if (*in < 0xF8) {
  272: 		if (inend - in < 4) break;
  273: 		val = (in[0]) & 0x07;
  274: 		val <<= 6;
  275: 		val |= (in[1]) & 0x3F;
  276: 		val <<= 6;
  277: 		val |= (in[2]) & 0x3F;
  278: 		val <<= 6;
  279: 		val |= (in[3]) & 0x3F;
  280: 		in += 4;
  281: 	    } else {
  282: 		xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
  283: 		in++;
  284: 		goto error;
  285: 	    }
  286: 	    if (!IS_CHAR(val)) {
  287: 		xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
  288: 		in++;
  289: 		goto error;
  290: 	    }
  291: 
  292: 	    /*
  293: 	     * We could do multiple things here. Just save as a char ref
  294: 	     */
  295: 	    out = xmlSerializeHexCharRef(out, val);
  296: 	} else if (IS_BYTE_CHAR(*in)) {
  297: 	    if (outend - out < 6) break;
  298: 	    out = xmlSerializeHexCharRef(out, *in++);
  299: 	} else {
  300: 	    xmlGenericError(xmlGenericErrorContext,
  301: 		"xmlEscapeEntities : char out of range\n");
  302: 	    in++;
  303: 	    goto error;
  304: 	}
  305:     }
  306:     *outlen = out - outstart;
  307:     *inlen = in - base;
  308:     return(0);
  309: error:
  310:     *outlen = out - outstart;
  311:     *inlen = in - base;
  312:     return(-1);
  313: }
  314: 
  315: /************************************************************************
  316:  *									*
  317:  *			Allocation and deallocation			*
  318:  *									*
  319:  ************************************************************************/
  320: /**
  321:  * xmlSaveCtxtInit:
  322:  * @ctxt: the saving context
  323:  *
  324:  * Initialize a saving context
  325:  */
  326: static void
  327: xmlSaveCtxtInit(xmlSaveCtxtPtr ctxt)
  328: {
  329:     int i;
  330:     int len;
  331: 
  332:     if (ctxt == NULL) return;
  333:     if ((ctxt->encoding == NULL) && (ctxt->escape == NULL))
  334:         ctxt->escape = xmlEscapeEntities;
  335:     len = xmlStrlen((xmlChar *)xmlTreeIndentString);
  336:     if ((xmlTreeIndentString == NULL) || (len == 0)) {
  337:         memset(&ctxt->indent[0], 0, MAX_INDENT + 1);
  338:     } else {
  339: 	ctxt->indent_size = len;
  340: 	ctxt->indent_nr = MAX_INDENT / ctxt->indent_size;
  341: 	for (i = 0;i < ctxt->indent_nr;i++)
  342: 	    memcpy(&ctxt->indent[i * ctxt->indent_size], xmlTreeIndentString,
  343: 		   ctxt->indent_size);
  344:         ctxt->indent[ctxt->indent_nr * ctxt->indent_size] = 0;
  345:     }
  346: 
  347:     if (xmlSaveNoEmptyTags) {
  348: 	ctxt->options |= XML_SAVE_NO_EMPTY;
  349:     }
  350: }
  351: 
  352: /**
  353:  * xmlFreeSaveCtxt:
  354:  *
  355:  * Free a saving context, destroying the ouptut in any remaining buffer
  356:  */
  357: static void
  358: xmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt)
  359: {
  360:     if (ctxt == NULL) return;
  361:     if (ctxt->encoding != NULL)
  362:         xmlFree((char *) ctxt->encoding);
  363:     if (ctxt->buf != NULL)
  364:         xmlOutputBufferClose(ctxt->buf);
  365:     xmlFree(ctxt);
  366: }
  367: 
  368: /**
  369:  * xmlNewSaveCtxt:
  370:  *
  371:  * Create a new saving context
  372:  *
  373:  * Returns the new structure or NULL in case of error
  374:  */
  375: static xmlSaveCtxtPtr
  376: xmlNewSaveCtxt(const char *encoding, int options)
  377: {
  378:     xmlSaveCtxtPtr ret;
  379: 
  380:     ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt));
  381:     if (ret == NULL) {
  382: 	xmlSaveErrMemory("creating saving context");
  383: 	return ( NULL );
  384:     }
  385:     memset(ret, 0, sizeof(xmlSaveCtxt));
  386: 
  387:     if (encoding != NULL) {
  388:         ret->handler = xmlFindCharEncodingHandler(encoding);
  389: 	if (ret->handler == NULL) {
  390: 	    xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
  391:             xmlFreeSaveCtxt(ret);
  392: 	    return(NULL);
  393: 	}
  394:         ret->encoding = xmlStrdup((const xmlChar *)encoding);
  395: 	ret->escape = NULL;
  396:     }
  397:     xmlSaveCtxtInit(ret);
  398: 
  399:     /*
  400:      * Use the options
  401:      */
  402: 
  403:     /* Re-check this option as it may already have been set */
  404:     if ((ret->options & XML_SAVE_NO_EMPTY) && ! (options & XML_SAVE_NO_EMPTY)) {
  405: 	options |= XML_SAVE_NO_EMPTY;
  406:     }
  407: 
  408:     ret->options = options;
  409:     if (options & XML_SAVE_FORMAT)
  410:         ret->format = 1;
  411:     else if (options & XML_SAVE_WSNONSIG)
  412:         ret->format = 2;
  413: 
  414:     return(ret);
  415: }
  416: 
  417: /************************************************************************
  418:  *									*
  419:  *   		Dumping XML tree content to a simple buffer		*
  420:  *									*
  421:  ************************************************************************/
  422: /**
  423:  * xmlAttrSerializeContent:
  424:  * @buf:  the XML buffer output
  425:  * @doc:  the document
  426:  * @attr:  the attribute pointer
  427:  *
  428:  * Serialize the attribute in the buffer
  429:  */
  430: static void
  431: xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr)
  432: {
  433:     xmlNodePtr children;
  434: 
  435:     children = attr->children;
  436:     while (children != NULL) {
  437:         switch (children->type) {
  438:             case XML_TEXT_NODE:
  439: 	        xmlAttrSerializeTxtContent(buf->buffer, attr->doc,
  440: 		                           attr, children->content);
  441: 		break;
  442:             case XML_ENTITY_REF_NODE:
  443:                 xmlBufferAdd(buf->buffer, BAD_CAST "&", 1);
  444:                 xmlBufferAdd(buf->buffer, children->name,
  445:                              xmlStrlen(children->name));
  446:                 xmlBufferAdd(buf->buffer, BAD_CAST ";", 1);
  447:                 break;
  448:             default:
  449:                 /* should not happen unless we have a badly built tree */
  450:                 break;
  451:         }
  452:         children = children->next;
  453:     }
  454: }
  455: 
  456: /************************************************************************
  457:  *									*
  458:  *   		Dumping XML tree content to an I/O output buffer	*
  459:  *									*
  460:  ************************************************************************/
  461: 
  462: static int xmlSaveSwitchEncoding(xmlSaveCtxtPtr ctxt, const char *encoding) {
  463:     xmlOutputBufferPtr buf = ctxt->buf;
  464: 
  465:     if ((encoding != NULL) && (buf->encoder == NULL) && (buf->conv == NULL)) {
  466: 	buf->encoder = xmlFindCharEncodingHandler((const char *)encoding);
  467: 	if (buf->encoder == NULL) {
  468: 	    xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL,
  469: 		       (const char *)encoding);
  470: 	    return(-1);
  471: 	}
  472: 	buf->conv = xmlBufferCreate();
  473: 	if (buf->conv == NULL) {
  474: 	    xmlCharEncCloseFunc(buf->encoder);
  475: 	    xmlSaveErrMemory("creating encoding buffer");
  476: 	    return(-1);
  477: 	}
  478: 	/*
  479: 	 * initialize the state, e.g. if outputting a BOM
  480: 	 */
  481: 	xmlCharEncOutFunc(buf->encoder, buf->conv, NULL);
  482:     }
  483:     return(0);
  484: }
  485: 
  486: static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) {
  487:     xmlOutputBufferPtr buf = ctxt->buf;
  488:     xmlOutputBufferFlush(buf);
  489:     xmlCharEncCloseFunc(buf->encoder);
  490:     xmlBufferFree(buf->conv);
  491:     buf->encoder = NULL;
  492:     buf->conv = NULL;
  493:     return(0);
  494: }
  495: 
  496: #ifdef LIBXML_HTML_ENABLED
  497: static void
  498: xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
  499: #endif
  500: static void xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
  501: static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
  502: void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
  503: static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur);
  504: 
  505: /**
  506:  * xmlOutputBufferWriteWSNonSig:
  507:  * @ctxt:  The save context
  508:  * @extra: Number of extra indents to apply to ctxt->level
  509:  *
  510:  * Write out formatting for non-significant whitespace output.
  511:  */
  512: static void
  513: xmlOutputBufferWriteWSNonSig(xmlSaveCtxtPtr ctxt, int extra)
  514: {
  515:     int i;
  516:     if ((ctxt == NULL) || (ctxt->buf == NULL))
  517:         return;
  518:     xmlOutputBufferWrite(ctxt->buf, 1, "\n");
  519:     for (i = 0; i < (ctxt->level + extra); i += ctxt->indent_nr) {
  520:         xmlOutputBufferWrite(ctxt->buf, ctxt->indent_size *
  521:                 ((ctxt->level + extra - i) > ctxt->indent_nr ?
  522:                  ctxt->indent_nr : (ctxt->level + extra - i)),
  523:                 ctxt->indent);
  524:     }
  525: }
  526: 
  527: /**
  528:  * xmlNsDumpOutput:
  529:  * @buf:  the XML buffer output
  530:  * @cur:  a namespace
  531:  * @ctxt: the output save context. Optional.
  532:  *
  533:  * Dump a local Namespace definition.
  534:  * Should be called in the context of attributes dumps.
  535:  * If @ctxt is supplied, @buf should be its buffer.
  536:  */
  537: static void
  538: xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur, xmlSaveCtxtPtr ctxt) {
  539:     if ((cur == NULL) || (buf == NULL)) return;
  540:     if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
  541: 	if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
  542: 	    return;
  543: 
  544: 	if (ctxt != NULL && ctxt->format == 2)
  545: 	    xmlOutputBufferWriteWSNonSig(ctxt, 2);
  546: 	else
  547: 	    xmlOutputBufferWrite(buf, 1, " ");
  548: 
  549:         /* Within the context of an element attributes */
  550: 	if (cur->prefix != NULL) {
  551: 	    xmlOutputBufferWrite(buf, 6, "xmlns:");
  552: 	    xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
  553: 	} else
  554: 	    xmlOutputBufferWrite(buf, 5, "xmlns");
  555: 	xmlOutputBufferWrite(buf, 1, "=");
  556: 	xmlBufferWriteQuotedString(buf->buffer, cur->href);
  557:     }
  558: }
  559: 
  560: /**
  561:  * xmlNsDumpOutputCtxt
  562:  * @ctxt: the save context
  563:  * @cur:  a namespace
  564:  *
  565:  * Dump a local Namespace definition to a save context.
  566:  * Should be called in the context of attribute dumps.
  567:  */
  568: static void
  569: xmlNsDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) {
  570:     xmlNsDumpOutput(ctxt->buf, cur, ctxt);
  571: }
  572: 
  573: /**
  574:  * xmlNsListDumpOutputCtxt
  575:  * @ctxt: the save context
  576:  * @cur:  the first namespace
  577:  *
  578:  * Dump a list of local namespace definitions to a save context.
  579:  * Should be called in the context of attribute dumps.
  580:  */
  581: static void
  582: xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) {
  583:     while (cur != NULL) {
  584:         xmlNsDumpOutput(ctxt->buf, cur, ctxt);
  585: 	cur = cur->next;
  586:     }
  587: }
  588: 
  589: /**
  590:  * xmlNsListDumpOutput:
  591:  * @buf:  the XML buffer output
  592:  * @cur:  the first namespace
  593:  *
  594:  * Dump a list of local Namespace definitions.
  595:  * Should be called in the context of attributes dumps.
  596:  */
  597: void
  598: xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
  599:     while (cur != NULL) {
  600:         xmlNsDumpOutput(buf, cur, NULL);
  601: 	cur = cur->next;
  602:     }
  603: }
  604: 
  605: /**
  606:  * xmlDtdDumpOutput:
  607:  * @buf:  the XML buffer output
  608:  * @dtd:  the pointer to the DTD
  609:  * 
  610:  * Dump the XML document DTD, if any.
  611:  */
  612: static void
  613: xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
  614:     xmlOutputBufferPtr buf;
  615:     int format, level;
  616:     xmlDocPtr doc;
  617: 
  618:     if (dtd == NULL) return;
  619:     if ((ctxt == NULL) || (ctxt->buf == NULL))
  620:         return;
  621:     buf = ctxt->buf;
  622:     xmlOutputBufferWrite(buf, 10, "<!DOCTYPE ");
  623:     xmlOutputBufferWriteString(buf, (const char *)dtd->name);
  624:     if (dtd->ExternalID != NULL) {
  625: 	xmlOutputBufferWrite(buf, 8, " PUBLIC ");
  626: 	xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
  627: 	xmlOutputBufferWrite(buf, 1, " ");
  628: 	xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
  629:     }  else if (dtd->SystemID != NULL) {
  630: 	xmlOutputBufferWrite(buf, 8, " SYSTEM ");
  631: 	xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
  632:     }
  633:     if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
  634:         (dtd->attributes == NULL) && (dtd->notations == NULL) &&
  635: 	(dtd->pentities == NULL)) {
  636: 	xmlOutputBufferWrite(buf, 1, ">");
  637: 	return;
  638:     }
  639:     xmlOutputBufferWrite(buf, 3, " [\n");
  640:     /*
  641:      * Dump the notations first they are not in the DTD children list
  642:      * Do this only on a standalone DTD or on the internal subset though.
  643:      */
  644:     if ((dtd->notations != NULL) && ((dtd->doc == NULL) ||
  645:         (dtd->doc->intSubset == dtd))) {
  646:         xmlDumpNotationTable(buf->buffer, (xmlNotationTablePtr) dtd->notations);
  647:     }
  648:     format = ctxt->format;
  649:     level = ctxt->level;
  650:     doc = ctxt->doc;
  651:     ctxt->format = 0;
  652:     ctxt->level = -1;
  653:     ctxt->doc = dtd->doc;
  654:     xmlNodeListDumpOutput(ctxt, dtd->children);
  655:     ctxt->format = format;
  656:     ctxt->level = level;
  657:     ctxt->doc = doc;
  658:     xmlOutputBufferWrite(buf, 2, "]>");
  659: }
  660: 
  661: /**
  662:  * xmlAttrDumpOutput:
  663:  * @buf:  the XML buffer output
  664:  * @cur:  the attribute pointer
  665:  *
  666:  * Dump an XML attribute
  667:  */
  668: static void
  669: xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
  670:     xmlOutputBufferPtr buf;
  671: 
  672:     if (cur == NULL) return;
  673:     buf = ctxt->buf;
  674:     if (buf == NULL) return;
  675:     if (ctxt->format == 2)
  676:         xmlOutputBufferWriteWSNonSig(ctxt, 2);
  677:     else
  678:         xmlOutputBufferWrite(buf, 1, " ");
  679:     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
  680:         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
  681: 	xmlOutputBufferWrite(buf, 1, ":");
  682:     }
  683:     xmlOutputBufferWriteString(buf, (const char *)cur->name);
  684:     xmlOutputBufferWrite(buf, 2, "=\"");
  685:     xmlAttrSerializeContent(buf, cur);
  686:     xmlOutputBufferWrite(buf, 1, "\"");
  687: }
  688: 
  689: /**
  690:  * xmlAttrListDumpOutput:
  691:  * @buf:  the XML buffer output
  692:  * @doc:  the document
  693:  * @cur:  the first attribute pointer
  694:  * @encoding:  an optional encoding string
  695:  *
  696:  * Dump a list of XML attributes
  697:  */
  698: static void
  699: xmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
  700:     if (cur == NULL) return;
  701:     while (cur != NULL) {
  702:         xmlAttrDumpOutput(ctxt, cur);
  703: 	cur = cur->next;
  704:     }
  705: }
  706: 
  707: 
  708: 
  709: /**
  710:  * xmlNodeListDumpOutput:
  711:  * @cur:  the first node
  712:  *
  713:  * Dump an XML node list, recursive behaviour, children are printed too.
  714:  */
  715: static void
  716: xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
  717:     xmlOutputBufferPtr buf;
  718: 
  719:     if (cur == NULL) return;
  720:     buf = ctxt->buf;
  721:     while (cur != NULL) {
  722: 	if ((ctxt->format == 1) && (xmlIndentTreeOutput) &&
  723: 	    ((cur->type == XML_ELEMENT_NODE) ||
  724: 	     (cur->type == XML_COMMENT_NODE) ||
  725: 	     (cur->type == XML_PI_NODE)))
  726: 	    xmlOutputBufferWrite(buf, ctxt->indent_size *
  727: 	                         (ctxt->level > ctxt->indent_nr ? 
  728: 				  ctxt->indent_nr : ctxt->level),
  729: 				 ctxt->indent);
  730:         xmlNodeDumpOutputInternal(ctxt, cur);
  731: 	if (ctxt->format == 1) {
  732: 	    xmlOutputBufferWrite(buf, 1, "\n");
  733: 	}
  734: 	cur = cur->next;
  735:     }
  736: }
  737: 
  738: #ifdef LIBXML_HTML_ENABLED
  739: /**
  740:  * xmlNodeDumpOutputInternal:
  741:  * @cur:  the current node
  742:  *
  743:  * Dump an HTML node, recursive behaviour, children are printed too.
  744:  */
  745: static int
  746: htmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
  747:     const xmlChar *oldenc = NULL;
  748:     const xmlChar *oldctxtenc = ctxt->encoding;
  749:     const xmlChar *encoding = ctxt->encoding;
  750:     xmlOutputBufferPtr buf = ctxt->buf;
  751:     int switched_encoding = 0;
  752:     xmlDocPtr doc;
  753: 
  754:     xmlInitParser();
  755: 
  756:     doc = cur->doc;
  757:     if (doc != NULL) {
  758:         oldenc = doc->encoding;
  759: 	if (ctxt->encoding != NULL) {
  760: 	    doc->encoding = BAD_CAST ctxt->encoding;
  761: 	} else if (doc->encoding != NULL) {
  762: 	    encoding = doc->encoding;
  763: 	}
  764:     }
  765: 
  766:     if ((encoding != NULL) && (doc != NULL))
  767: 	htmlSetMetaEncoding(doc, (const xmlChar *) encoding);
  768:     if ((encoding == NULL) && (doc != NULL))
  769: 	encoding = htmlGetMetaEncoding(doc);
  770:     if (encoding == NULL)
  771: 	encoding = BAD_CAST "HTML";
  772:     if ((encoding != NULL) && (oldctxtenc == NULL) &&
  773: 	(buf->encoder == NULL) && (buf->conv == NULL)) {
  774: 	if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
  775: 	    doc->encoding = oldenc;
  776: 	    return(-1);
  777: 	}
  778: 	switched_encoding = 1;
  779:     }
  780:     if (ctxt->options & XML_SAVE_FORMAT)
  781: 	htmlNodeDumpFormatOutput(buf, doc, cur,
  782: 				       (const char *)encoding, 1);
  783:     else
  784: 	htmlNodeDumpFormatOutput(buf, doc, cur,
  785: 				       (const char *)encoding, 0);
  786:     /*
  787:      * Restore the state of the saving context at the end of the document
  788:      */
  789:     if ((switched_encoding) && (oldctxtenc == NULL)) {
  790: 	xmlSaveClearEncoding(ctxt);
  791:     }
  792:     if (doc != NULL)
  793: 	doc->encoding = oldenc;
  794:     return(0);
  795: }
  796: #endif
  797: 
  798: /**
  799:  * xmlNodeDumpOutputInternal:
  800:  * @cur:  the current node
  801:  *
  802:  * Dump an XML node, recursive behaviour, children are printed too.
  803:  */
  804: static void
  805: xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
  806:     int format;
  807:     xmlNodePtr tmp;
  808:     xmlChar *start, *end;
  809:     xmlOutputBufferPtr buf;
  810: 
  811:     if (cur == NULL) return;
  812:     buf = ctxt->buf;
  813:     if (cur->type == XML_XINCLUDE_START)
  814: 	return;
  815:     if (cur->type == XML_XINCLUDE_END)
  816: 	return;
  817:     if ((cur->type == XML_DOCUMENT_NODE) ||
  818:         (cur->type == XML_HTML_DOCUMENT_NODE)) {
  819: 	xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
  820: 	return;
  821:     }
  822: #ifdef LIBXML_HTML_ENABLED
  823:     if (ctxt->options & XML_SAVE_XHTML) {
  824:         xhtmlNodeDumpOutput(ctxt, cur);
  825:         return;
  826:     }
  827:     if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
  828:          (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
  829:          ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
  830:         (ctxt->options & XML_SAVE_AS_HTML)) {
  831: 	htmlNodeDumpOutputInternal(ctxt, cur);
  832: 	return;
  833:     }
  834: #endif
  835:     if (cur->type == XML_DTD_NODE) {
  836:         xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
  837: 	return;
  838:     }
  839:     if (cur->type == XML_DOCUMENT_FRAG_NODE) {
  840:         xmlNodeListDumpOutput(ctxt, cur->children);
  841: 	return;
  842:     }
  843:     if (cur->type == XML_ELEMENT_DECL) {
  844:         xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
  845: 	return;
  846:     }
  847:     if (cur->type == XML_ATTRIBUTE_DECL) {
  848:         xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
  849: 	return;
  850:     }
  851:     if (cur->type == XML_ENTITY_DECL) {
  852:         xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
  853: 	return;
  854:     }
  855:     if (cur->type == XML_TEXT_NODE) {
  856: 	if (cur->content != NULL) {
  857: 	    if (cur->name != xmlStringTextNoenc) {
  858:                 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
  859: 	    } else {
  860: 		/*
  861: 		 * Disable escaping, needed for XSLT
  862: 		 */
  863: 		xmlOutputBufferWriteString(buf, (const char *) cur->content);
  864: 	    }
  865: 	}
  866: 
  867: 	return;
  868:     }
  869:     if (cur->type == XML_PI_NODE) {
  870: 	if (cur->content != NULL) {
  871: 	    xmlOutputBufferWrite(buf, 2, "<?");
  872: 	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
  873: 	    if (cur->content != NULL) {
  874: 	        if (ctxt->format == 2)
  875: 	            xmlOutputBufferWriteWSNonSig(ctxt, 0);
  876: 	        else
  877: 	            xmlOutputBufferWrite(buf, 1, " ");
  878: 		xmlOutputBufferWriteString(buf, (const char *)cur->content);
  879: 	    }
  880: 	    xmlOutputBufferWrite(buf, 2, "?>");
  881: 	} else {
  882: 	    xmlOutputBufferWrite(buf, 2, "<?");
  883: 	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
  884: 	    if (ctxt->format == 2)
  885: 	        xmlOutputBufferWriteWSNonSig(ctxt, 0);
  886: 	    xmlOutputBufferWrite(buf, 2, "?>");
  887: 	}
  888: 	return;
  889:     }
  890:     if (cur->type == XML_COMMENT_NODE) {
  891: 	if (cur->content != NULL) {
  892: 	    xmlOutputBufferWrite(buf, 4, "<!--");
  893: 	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
  894: 	    xmlOutputBufferWrite(buf, 3, "-->");
  895: 	}
  896: 	return;
  897:     }
  898:     if (cur->type == XML_ENTITY_REF_NODE) {
  899:         xmlOutputBufferWrite(buf, 1, "&");
  900: 	xmlOutputBufferWriteString(buf, (const char *)cur->name);
  901:         xmlOutputBufferWrite(buf, 1, ";");
  902: 	return;
  903:     }
  904:     if (cur->type == XML_CDATA_SECTION_NODE) {
  905: 	if (cur->content == NULL || *cur->content == '\0') {
  906: 	    xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
  907: 	} else {
  908: 	    start = end = cur->content;
  909: 	    while (*end != '\0') {
  910: 		if ((*end == ']') && (*(end + 1) == ']') &&
  911: 		    (*(end + 2) == '>')) {
  912: 		    end = end + 2;
  913: 		    xmlOutputBufferWrite(buf, 9, "<![CDATA[");
  914: 		    xmlOutputBufferWrite(buf, end - start, (const char *)start);
  915: 		    xmlOutputBufferWrite(buf, 3, "]]>");
  916: 		    start = end;
  917: 		}
  918: 		end++;
  919: 	    }
  920: 	    if (start != end) {
  921: 		xmlOutputBufferWrite(buf, 9, "<![CDATA[");
  922: 		xmlOutputBufferWriteString(buf, (const char *)start);
  923: 		xmlOutputBufferWrite(buf, 3, "]]>");
  924: 	    }
  925: 	}
  926: 	return;
  927:     }
  928:     if (cur->type == XML_ATTRIBUTE_NODE) {
  929: 	xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
  930: 	return;
  931:     }
  932:     if (cur->type == XML_NAMESPACE_DECL) {
  933: 	xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
  934: 	return;
  935:     }
  936: 
  937:     format = ctxt->format;
  938:     if (format == 1) {
  939: 	tmp = cur->children;
  940: 	while (tmp != NULL) {
  941: 	    if ((tmp->type == XML_TEXT_NODE) ||
  942: 		(tmp->type == XML_CDATA_SECTION_NODE) ||
  943: 		(tmp->type == XML_ENTITY_REF_NODE)) {
  944: 		ctxt->format = 0;
  945: 		break;
  946: 	    }
  947: 	    tmp = tmp->next;
  948: 	}
  949:     }
  950:     xmlOutputBufferWrite(buf, 1, "<");
  951:     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
  952:         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
  953: 	xmlOutputBufferWrite(buf, 1, ":");
  954:     }
  955: 
  956:     xmlOutputBufferWriteString(buf, (const char *)cur->name);
  957:     if (cur->nsDef)
  958:         xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
  959:     if (cur->properties != NULL)
  960:         xmlAttrListDumpOutput(ctxt, cur->properties);
  961: 
  962:     if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
  963: 	(cur->children == NULL) && ((ctxt->options & XML_SAVE_NO_EMPTY) == 0)) {
  964:         if (ctxt->format == 2)
  965:             xmlOutputBufferWriteWSNonSig(ctxt, 0);
  966:         xmlOutputBufferWrite(buf, 2, "/>");
  967: 	ctxt->format = format;
  968: 	return;
  969:     }
  970:     if (ctxt->format == 2)
  971:         xmlOutputBufferWriteWSNonSig(ctxt, 1);
  972:     xmlOutputBufferWrite(buf, 1, ">");
  973:     if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
  974: 	xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
  975:     }
  976:     if (cur->children != NULL) {
  977: 	if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
  978: 	if (ctxt->level >= 0) ctxt->level++;
  979: 	xmlNodeListDumpOutput(ctxt, cur->children);
  980: 	if (ctxt->level > 0) ctxt->level--;
  981: 	if ((xmlIndentTreeOutput) && (ctxt->format == 1))
  982: 	    xmlOutputBufferWrite(buf, ctxt->indent_size *
  983: 	                         (ctxt->level > ctxt->indent_nr ? 
  984: 				  ctxt->indent_nr : ctxt->level),
  985: 				 ctxt->indent);
  986:     }
  987:     xmlOutputBufferWrite(buf, 2, "</");
  988:     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
  989:         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
  990: 	xmlOutputBufferWrite(buf, 1, ":");
  991:     }
  992: 
  993:     xmlOutputBufferWriteString(buf, (const char *)cur->name);
  994:     if (ctxt->format == 2)
  995:         xmlOutputBufferWriteWSNonSig(ctxt, 0);
  996:     xmlOutputBufferWrite(buf, 1, ">");
  997:     ctxt->format = format;
  998: }
  999: 
 1000: /**
 1001:  * xmlDocContentDumpOutput:
 1002:  * @cur:  the document
 1003:  *
 1004:  * Dump an XML document.
 1005:  */
 1006: static int
 1007: xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) {
 1008: #ifdef LIBXML_HTML_ENABLED
 1009:     xmlDtdPtr dtd;
 1010:     int is_xhtml = 0;
 1011: #endif
 1012:     const xmlChar *oldenc = cur->encoding;
 1013:     const xmlChar *oldctxtenc = ctxt->encoding;
 1014:     const xmlChar *encoding = ctxt->encoding;
 1015:     xmlCharEncodingOutputFunc oldescape = ctxt->escape;
 1016:     xmlCharEncodingOutputFunc oldescapeAttr = ctxt->escapeAttr;
 1017:     xmlOutputBufferPtr buf = ctxt->buf;
 1018:     xmlCharEncoding enc;
 1019:     int switched_encoding = 0;
 1020: 
 1021:     xmlInitParser();
 1022: 
 1023:     if ((cur->type != XML_HTML_DOCUMENT_NODE) &&
 1024:         (cur->type != XML_DOCUMENT_NODE))
 1025: 	 return(-1);
 1026: 
 1027:     if (ctxt->encoding != NULL) {
 1028:         cur->encoding = BAD_CAST ctxt->encoding;
 1029:     } else if (cur->encoding != NULL) {
 1030: 	encoding = cur->encoding;
 1031:     } else if (cur->charset != XML_CHAR_ENCODING_UTF8) {
 1032: 	encoding = (const xmlChar *)
 1033: 		     xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
 1034:     }
 1035: 
 1036:     if (((cur->type == XML_HTML_DOCUMENT_NODE) &&
 1037:          ((ctxt->options & XML_SAVE_AS_XML) == 0) &&
 1038:          ((ctxt->options & XML_SAVE_XHTML) == 0)) ||
 1039:         (ctxt->options & XML_SAVE_AS_HTML)) {
 1040: #ifdef LIBXML_HTML_ENABLED
 1041:         if (encoding != NULL)
 1042: 	    htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
 1043:         if (encoding == NULL)
 1044: 	    encoding = htmlGetMetaEncoding(cur);
 1045:         if (encoding == NULL)
 1046: 	    encoding = BAD_CAST "HTML";
 1047: 	if ((encoding != NULL) && (oldctxtenc == NULL) &&
 1048: 	    (buf->encoder == NULL) && (buf->conv == NULL)) {
 1049: 	    if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
 1050: 		cur->encoding = oldenc;
 1051: 		return(-1);
 1052: 	    }
 1053: 	}
 1054:         if (ctxt->options & XML_SAVE_FORMAT)
 1055: 	    htmlDocContentDumpFormatOutput(buf, cur,
 1056: 	                                   (const char *)encoding, 1);
 1057: 	else
 1058: 	    htmlDocContentDumpFormatOutput(buf, cur,
 1059: 	                                   (const char *)encoding, 0);
 1060: 	if (ctxt->encoding != NULL)
 1061: 	    cur->encoding = oldenc;
 1062: 	return(0);
 1063: #else
 1064:         return(-1);
 1065: #endif
 1066:     } else if ((cur->type == XML_DOCUMENT_NODE) ||
 1067:                (ctxt->options & XML_SAVE_AS_XML) ||
 1068:                (ctxt->options & XML_SAVE_XHTML)) {
 1069: 	enc = xmlParseCharEncoding((const char*) encoding);
 1070: 	if ((encoding != NULL) && (oldctxtenc == NULL) &&
 1071: 	    (buf->encoder == NULL) && (buf->conv == NULL) &&
 1072: 	    ((ctxt->options & XML_SAVE_NO_DECL) == 0)) {
 1073: 	    if ((enc != XML_CHAR_ENCODING_UTF8) &&
 1074: 		(enc != XML_CHAR_ENCODING_NONE) &&
 1075: 		(enc != XML_CHAR_ENCODING_ASCII)) {
 1076: 		/*
 1077: 		 * we need to switch to this encoding but just for this
 1078: 		 * document since we output the XMLDecl the conversion
 1079: 		 * must be done to not generate not well formed documents.
 1080: 		 */
 1081: 		if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
 1082: 		    cur->encoding = oldenc;
 1083: 		    return(-1);
 1084: 		}
 1085: 		switched_encoding = 1;
 1086: 	    }
 1087: 	    if (ctxt->escape == xmlEscapeEntities)
 1088: 		ctxt->escape = NULL;
 1089: 	    if (ctxt->escapeAttr == xmlEscapeEntities)
 1090: 		ctxt->escapeAttr = NULL;
 1091: 	}
 1092: 
 1093: 
 1094: 	/*
 1095: 	 * Save the XML declaration
 1096: 	 */
 1097: 	if ((ctxt->options & XML_SAVE_NO_DECL) == 0) {
 1098: 	    xmlOutputBufferWrite(buf, 14, "<?xml version=");
 1099: 	    if (cur->version != NULL) 
 1100: 		xmlBufferWriteQuotedString(buf->buffer, cur->version);
 1101: 	    else
 1102: 		xmlOutputBufferWrite(buf, 5, "\"1.0\"");
 1103: 	    if (encoding != NULL) {
 1104: 		xmlOutputBufferWrite(buf, 10, " encoding=");
 1105: 		xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
 1106: 	    }
 1107: 	    switch (cur->standalone) {
 1108: 		case 0:
 1109: 		    xmlOutputBufferWrite(buf, 16, " standalone=\"no\"");
 1110: 		    break;
 1111: 		case 1:
 1112: 		    xmlOutputBufferWrite(buf, 17, " standalone=\"yes\"");
 1113: 		    break;
 1114: 	    }
 1115: 	    xmlOutputBufferWrite(buf, 3, "?>\n");
 1116: 	}
 1117: 
 1118: #ifdef LIBXML_HTML_ENABLED
 1119:         if (ctxt->options & XML_SAVE_XHTML)
 1120:             is_xhtml = 1;
 1121: 	if ((ctxt->options & XML_SAVE_NO_XHTML) == 0) {
 1122: 	    dtd = xmlGetIntSubset(cur);
 1123: 	    if (dtd != NULL) {
 1124: 		is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
 1125: 		if (is_xhtml < 0) is_xhtml = 0;
 1126: 	    }
 1127: 	}
 1128: #endif
 1129: 	if (cur->children != NULL) {
 1130: 	    xmlNodePtr child = cur->children;
 1131: 
 1132: 	    while (child != NULL) {
 1133: 		ctxt->level = 0;
 1134: #ifdef LIBXML_HTML_ENABLED
 1135: 		if (is_xhtml)
 1136: 		    xhtmlNodeDumpOutput(ctxt, child);
 1137: 		else
 1138: #endif
 1139: 		    xmlNodeDumpOutputInternal(ctxt, child);
 1140: 		xmlOutputBufferWrite(buf, 1, "\n");
 1141: 		child = child->next;
 1142: 	    }
 1143: 	}
 1144:     }
 1145: 
 1146:     /*
 1147:      * Restore the state of the saving context at the end of the document
 1148:      */
 1149:     if ((switched_encoding) && (oldctxtenc == NULL)) {
 1150: 	xmlSaveClearEncoding(ctxt);
 1151: 	ctxt->escape = oldescape;
 1152: 	ctxt->escapeAttr = oldescapeAttr;
 1153:     }
 1154:     cur->encoding = oldenc;
 1155:     return(0);
 1156: }
 1157: 
 1158: #ifdef LIBXML_HTML_ENABLED
 1159: /************************************************************************
 1160:  *									*
 1161:  *		Functions specific to XHTML serialization		*
 1162:  *									*
 1163:  ************************************************************************/
 1164: 
 1165: /**
 1166:  * xhtmlIsEmpty:
 1167:  * @node:  the node
 1168:  *
 1169:  * Check if a node is an empty xhtml node
 1170:  *
 1171:  * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
 1172:  */
 1173: static int
 1174: xhtmlIsEmpty(xmlNodePtr node) {
 1175:     if (node == NULL)
 1176: 	return(-1);
 1177:     if (node->type != XML_ELEMENT_NODE)
 1178: 	return(0);
 1179:     if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
 1180: 	return(0);
 1181:     if (node->children != NULL)
 1182: 	return(0);
 1183:     switch (node->name[0]) {
 1184: 	case 'a':
 1185: 	    if (xmlStrEqual(node->name, BAD_CAST "area"))
 1186: 		return(1);
 1187: 	    return(0);
 1188: 	case 'b':
 1189: 	    if (xmlStrEqual(node->name, BAD_CAST "br"))
 1190: 		return(1);
 1191: 	    if (xmlStrEqual(node->name, BAD_CAST "base"))
 1192: 		return(1);
 1193: 	    if (xmlStrEqual(node->name, BAD_CAST "basefont"))
 1194: 		return(1);
 1195: 	    return(0);
 1196: 	case 'c':
 1197: 	    if (xmlStrEqual(node->name, BAD_CAST "col"))
 1198: 		return(1);
 1199: 	    return(0);
 1200: 	case 'f':
 1201: 	    if (xmlStrEqual(node->name, BAD_CAST "frame"))
 1202: 		return(1);
 1203: 	    return(0);
 1204: 	case 'h':
 1205: 	    if (xmlStrEqual(node->name, BAD_CAST "hr"))
 1206: 		return(1);
 1207: 	    return(0);
 1208: 	case 'i':
 1209: 	    if (xmlStrEqual(node->name, BAD_CAST "img"))
 1210: 		return(1);
 1211: 	    if (xmlStrEqual(node->name, BAD_CAST "input"))
 1212: 		return(1);
 1213: 	    if (xmlStrEqual(node->name, BAD_CAST "isindex"))
 1214: 		return(1);
 1215: 	    return(0);
 1216: 	case 'l':
 1217: 	    if (xmlStrEqual(node->name, BAD_CAST "link"))
 1218: 		return(1);
 1219: 	    return(0);
 1220: 	case 'm':
 1221: 	    if (xmlStrEqual(node->name, BAD_CAST "meta"))
 1222: 		return(1);
 1223: 	    return(0);
 1224: 	case 'p':
 1225: 	    if (xmlStrEqual(node->name, BAD_CAST "param"))
 1226: 		return(1);
 1227: 	    return(0);
 1228:     }
 1229:     return(0);
 1230: }
 1231: 
 1232: /**
 1233:  * xhtmlAttrListDumpOutput:
 1234:  * @cur:  the first attribute pointer
 1235:  *
 1236:  * Dump a list of XML attributes
 1237:  */
 1238: static void
 1239: xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
 1240:     xmlAttrPtr xml_lang = NULL;
 1241:     xmlAttrPtr lang = NULL;
 1242:     xmlAttrPtr name = NULL;
 1243:     xmlAttrPtr id = NULL;
 1244:     xmlNodePtr parent;
 1245:     xmlOutputBufferPtr buf;
 1246: 
 1247:     if (cur == NULL) return;
 1248:     buf = ctxt->buf;
 1249:     parent = cur->parent;
 1250:     while (cur != NULL) {
 1251: 	if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
 1252: 	    id = cur;
 1253: 	else
 1254: 	if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
 1255: 	    name = cur;
 1256: 	else
 1257: 	if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
 1258: 	    lang = cur;
 1259: 	else
 1260: 	if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
 1261: 	    (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
 1262: 	    xml_lang = cur;
 1263: 	else if ((cur->ns == NULL) && 
 1264: 		 ((cur->children == NULL) ||
 1265: 		  (cur->children->content == NULL) ||
 1266: 		  (cur->children->content[0] == 0)) &&
 1267: 		 (htmlIsBooleanAttr(cur->name))) {
 1268: 	    if (cur->children != NULL)
 1269: 		xmlFreeNode(cur->children);
 1270: 	    cur->children = xmlNewText(cur->name);
 1271: 	    if (cur->children != NULL)
 1272: 		cur->children->parent = (xmlNodePtr) cur;
 1273: 	}
 1274:         xmlAttrDumpOutput(ctxt, cur);
 1275: 	cur = cur->next;
 1276:     }
 1277:     /*
 1278:      * C.8
 1279:      */
 1280:     if ((name != NULL) && (id == NULL)) {
 1281: 	if ((parent != NULL) && (parent->name != NULL) &&
 1282: 	    ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
 1283: 	     (xmlStrEqual(parent->name, BAD_CAST "p")) ||
 1284: 	     (xmlStrEqual(parent->name, BAD_CAST "div")) ||
 1285: 	     (xmlStrEqual(parent->name, BAD_CAST "img")) ||
 1286: 	     (xmlStrEqual(parent->name, BAD_CAST "map")) ||
 1287: 	     (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
 1288: 	     (xmlStrEqual(parent->name, BAD_CAST "form")) ||
 1289: 	     (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
 1290: 	     (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
 1291: 	    xmlOutputBufferWrite(buf, 5, " id=\"");
 1292: 	    xmlAttrSerializeContent(buf, name);
 1293: 	    xmlOutputBufferWrite(buf, 1, "\"");
 1294: 	}
 1295:     }
 1296:     /*
 1297:      * C.7.
 1298:      */
 1299:     if ((lang != NULL) && (xml_lang == NULL)) {
 1300: 	xmlOutputBufferWrite(buf, 11, " xml:lang=\"");
 1301: 	xmlAttrSerializeContent(buf, lang);
 1302: 	xmlOutputBufferWrite(buf, 1, "\"");
 1303:     } else 
 1304:     if ((xml_lang != NULL) && (lang == NULL)) {
 1305: 	xmlOutputBufferWrite(buf, 7, " lang=\"");
 1306: 	xmlAttrSerializeContent(buf, xml_lang);
 1307: 	xmlOutputBufferWrite(buf, 1, "\"");
 1308:     }
 1309: }
 1310: 
 1311: /**
 1312:  * xhtmlNodeListDumpOutput:
 1313:  * @buf:  the XML buffer output
 1314:  * @doc:  the XHTML document
 1315:  * @cur:  the first node
 1316:  * @level: the imbrication level for indenting
 1317:  * @format: is formatting allowed
 1318:  * @encoding:  an optional encoding string
 1319:  *
 1320:  * Dump an XML node list, recursive behaviour, children are printed too.
 1321:  * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
 1322:  * or xmlKeepBlanksDefault(0) was called
 1323:  */
 1324: static void
 1325: xhtmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
 1326:     xmlOutputBufferPtr buf;
 1327: 
 1328:     if (cur == NULL) return;
 1329:     buf = ctxt->buf;
 1330:     while (cur != NULL) {
 1331: 	if ((ctxt->format == 1) && (xmlIndentTreeOutput) &&
 1332: 	    (cur->type == XML_ELEMENT_NODE))
 1333: 	    xmlOutputBufferWrite(buf, ctxt->indent_size *
 1334: 	                         (ctxt->level > ctxt->indent_nr ? 
 1335: 				  ctxt->indent_nr : ctxt->level),
 1336: 				 ctxt->indent);
 1337:         xhtmlNodeDumpOutput(ctxt, cur);
 1338: 	if (ctxt->format == 1) {
 1339: 	    xmlOutputBufferWrite(buf, 1, "\n");
 1340: 	}
 1341: 	cur = cur->next;
 1342:     }
 1343: }
 1344: 
 1345: /**
 1346:  * xhtmlNodeDumpOutput:
 1347:  * @buf:  the XML buffer output
 1348:  * @doc:  the XHTML document
 1349:  * @cur:  the current node
 1350:  * @level: the imbrication level for indenting
 1351:  * @format: is formatting allowed
 1352:  * @encoding:  an optional encoding string
 1353:  *
 1354:  * Dump an XHTML node, recursive behaviour, children are printed too.
 1355:  */
 1356: static void
 1357: xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
 1358:     int format, addmeta = 0;
 1359:     xmlNodePtr tmp;
 1360:     xmlChar *start, *end;
 1361:     xmlOutputBufferPtr buf;
 1362: 
 1363:     if (cur == NULL) return;
 1364:     if ((cur->type == XML_DOCUMENT_NODE) ||
 1365:         (cur->type == XML_HTML_DOCUMENT_NODE)) {
 1366:         xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
 1367: 	return;
 1368:     }
 1369:     if (cur->type == XML_XINCLUDE_START)
 1370: 	return;
 1371:     if (cur->type == XML_XINCLUDE_END)
 1372: 	return;
 1373:     if (cur->type == XML_DTD_NODE) {
 1374:         xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
 1375: 	return;
 1376:     }
 1377:     if (cur->type == XML_DOCUMENT_FRAG_NODE) {
 1378:         xhtmlNodeListDumpOutput(ctxt, cur->children);
 1379: 	return;
 1380:     }
 1381:     buf = ctxt->buf;
 1382:     if (cur->type == XML_ELEMENT_DECL) {
 1383:         xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
 1384: 	return;
 1385:     }
 1386:     if (cur->type == XML_ATTRIBUTE_DECL) {
 1387:         xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
 1388: 	return;
 1389:     }
 1390:     if (cur->type == XML_ENTITY_DECL) {
 1391:         xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
 1392: 	return;
 1393:     }
 1394:     if (cur->type == XML_TEXT_NODE) {
 1395: 	if (cur->content != NULL) {
 1396: 	    if ((cur->name == xmlStringText) ||
 1397: 		(cur->name != xmlStringTextNoenc)) {
 1398:                 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
 1399: 	    } else {
 1400: 		/*
 1401: 		 * Disable escaping, needed for XSLT
 1402: 		 */
 1403: 		xmlOutputBufferWriteString(buf, (const char *) cur->content);
 1404: 	    }
 1405: 	}
 1406: 
 1407: 	return;
 1408:     }
 1409:     if (cur->type == XML_PI_NODE) {
 1410: 	if (cur->content != NULL) {
 1411: 	    xmlOutputBufferWrite(buf, 2, "<?");
 1412: 	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
 1413: 	    if (cur->content != NULL) {
 1414: 		xmlOutputBufferWrite(buf, 1, " ");
 1415: 		xmlOutputBufferWriteString(buf, (const char *)cur->content);
 1416: 	    }
 1417: 	    xmlOutputBufferWrite(buf, 2, "?>");
 1418: 	} else {
 1419: 	    xmlOutputBufferWrite(buf, 2, "<?");
 1420: 	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
 1421: 	    xmlOutputBufferWrite(buf, 2, "?>");
 1422: 	}
 1423: 	return;
 1424:     }
 1425:     if (cur->type == XML_COMMENT_NODE) {
 1426: 	if (cur->content != NULL) {
 1427: 	    xmlOutputBufferWrite(buf, 4, "<!--");
 1428: 	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
 1429: 	    xmlOutputBufferWrite(buf, 3, "-->");
 1430: 	}
 1431: 	return;
 1432:     }
 1433:     if (cur->type == XML_ENTITY_REF_NODE) {
 1434:         xmlOutputBufferWrite(buf, 1, "&");
 1435: 	xmlOutputBufferWriteString(buf, (const char *)cur->name);
 1436:         xmlOutputBufferWrite(buf, 1, ";");
 1437: 	return;
 1438:     }
 1439:     if (cur->type == XML_CDATA_SECTION_NODE) {
 1440: 	if (cur->content == NULL || *cur->content == '\0') {
 1441: 	    xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
 1442: 	} else {
 1443: 	    start = end = cur->content;
 1444: 	    while (*end != '\0') {
 1445: 		if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') {
 1446: 		    end = end + 2;
 1447: 		    xmlOutputBufferWrite(buf, 9, "<![CDATA[");
 1448: 		    xmlOutputBufferWrite(buf, end - start, (const char *)start);
 1449: 		    xmlOutputBufferWrite(buf, 3, "]]>");
 1450: 		    start = end;
 1451: 		}
 1452: 		end++;
 1453: 	    }
 1454: 	    if (start != end) {
 1455: 		xmlOutputBufferWrite(buf, 9, "<![CDATA[");
 1456: 		xmlOutputBufferWriteString(buf, (const char *)start);
 1457: 		xmlOutputBufferWrite(buf, 3, "]]>");
 1458: 	    }
 1459: 	}
 1460: 	return;
 1461:     }
 1462:     if (cur->type == XML_ATTRIBUTE_NODE) {
 1463:         xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
 1464: 	return;
 1465:     }
 1466: 
 1467:     format = ctxt->format;
 1468:     if (format == 1) {
 1469: 	tmp = cur->children;
 1470: 	while (tmp != NULL) {
 1471: 	    if ((tmp->type == XML_TEXT_NODE) || 
 1472: 		(tmp->type == XML_ENTITY_REF_NODE)) {
 1473: 		format = 0;
 1474: 		break;
 1475: 	    }
 1476: 	    tmp = tmp->next;
 1477: 	}
 1478:     }
 1479:     xmlOutputBufferWrite(buf, 1, "<");
 1480:     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
 1481:         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
 1482: 	xmlOutputBufferWrite(buf, 1, ":");
 1483:     }
 1484: 
 1485:     xmlOutputBufferWriteString(buf, (const char *)cur->name);
 1486:     if (cur->nsDef)
 1487:         xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
 1488:     if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
 1489: 	(cur->ns == NULL) && (cur->nsDef == NULL))) {
 1490: 	/*
 1491: 	 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
 1492: 	 */
 1493: 	xmlOutputBufferWriteString(buf,
 1494: 		" xmlns=\"http://www.w3.org/1999/xhtml\"");
 1495:     }
 1496:     if (cur->properties != NULL)
 1497:         xhtmlAttrListDumpOutput(ctxt, cur->properties);
 1498: 
 1499: 	if ((cur->type == XML_ELEMENT_NODE) && 
 1500: 		(cur->parent != NULL) && 
 1501: 		(cur->parent->parent == (xmlNodePtr) cur->doc) && 
 1502: 		xmlStrEqual(cur->name, BAD_CAST"head") && 
 1503: 		xmlStrEqual(cur->parent->name, BAD_CAST"html")) {
 1504: 
 1505: 		tmp = cur->children;
 1506: 		while (tmp != NULL) {
 1507: 			if (xmlStrEqual(tmp->name, BAD_CAST"meta")) {
 1508: 				xmlChar *httpequiv;
 1509: 
 1510: 				httpequiv = xmlGetProp(tmp, BAD_CAST"http-equiv");
 1511: 				if (httpequiv != NULL) {
 1512: 					if (xmlStrcasecmp(httpequiv, BAD_CAST"Content-Type") == 0) {
 1513: 						xmlFree(httpequiv);
 1514: 						break;
 1515: 					}
 1516: 					xmlFree(httpequiv);
 1517: 				}
 1518: 			}
 1519: 			tmp = tmp->next;
 1520: 		}
 1521: 		if (tmp == NULL)
 1522: 			addmeta = 1;
 1523: 	}
 1524: 
 1525:     if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
 1526: 	if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
 1527: 	    ((xhtmlIsEmpty(cur) == 1) && (addmeta == 0))) {
 1528: 	    /*
 1529: 	     * C.2. Empty Elements
 1530: 	     */
 1531: 	    xmlOutputBufferWrite(buf, 3, " />");
 1532: 	} else {
 1533: 		if (addmeta == 1) {
 1534: 			xmlOutputBufferWrite(buf, 1, ">");
 1535: 			if (ctxt->format == 1) {
 1536: 				xmlOutputBufferWrite(buf, 1, "\n");
 1537: 				if (xmlIndentTreeOutput)
 1538: 					xmlOutputBufferWrite(buf, ctxt->indent_size *
 1539: 					(ctxt->level + 1 > ctxt->indent_nr ? 
 1540: 					ctxt->indent_nr : ctxt->level + 1), ctxt->indent);
 1541: 			}
 1542: 			xmlOutputBufferWriteString(buf,
 1543: 				"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=");
 1544: 			if (ctxt->encoding) {
 1545: 				xmlOutputBufferWriteString(buf, (const char *)ctxt->encoding);
 1546: 			} else {
 1547: 				xmlOutputBufferWrite(buf, 5, "UTF-8");
 1548: 			}
 1549: 			xmlOutputBufferWrite(buf, 4, "\" />");
 1550: 			if (ctxt->format == 1)
 1551: 				xmlOutputBufferWrite(buf, 1, "\n");
 1552: 		} else {
 1553: 			xmlOutputBufferWrite(buf, 1, ">");
 1554: 		}
 1555: 	    /*
 1556: 	     * C.3. Element Minimization and Empty Element Content
 1557: 	     */
 1558: 	    xmlOutputBufferWrite(buf, 2, "</");
 1559: 	    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
 1560: 		xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
 1561: 		xmlOutputBufferWrite(buf, 1, ":");
 1562: 	    }
 1563: 	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
 1564: 	    xmlOutputBufferWrite(buf, 1, ">");
 1565: 	}
 1566: 	return;
 1567:     }
 1568:     xmlOutputBufferWrite(buf, 1, ">");
 1569: 	if (addmeta == 1) {
 1570: 		if (ctxt->format == 1) {
 1571: 			xmlOutputBufferWrite(buf, 1, "\n");
 1572: 			if (xmlIndentTreeOutput)
 1573: 				xmlOutputBufferWrite(buf, ctxt->indent_size *
 1574: 				(ctxt->level + 1 > ctxt->indent_nr ? 
 1575: 				ctxt->indent_nr : ctxt->level + 1), ctxt->indent);
 1576: 		}
 1577: 		xmlOutputBufferWriteString(buf,
 1578: 			"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=");
 1579: 		if (ctxt->encoding) {
 1580: 			xmlOutputBufferWriteString(buf, (const char *)ctxt->encoding);
 1581: 		} else {
 1582: 			xmlOutputBufferWrite(buf, 5, "UTF-8");
 1583: 		}
 1584: 		xmlOutputBufferWrite(buf, 4, "\" />");
 1585: 	}
 1586:     if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
 1587: 	xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
 1588:     }
 1589: 
 1590: #if 0
 1591:     /*
 1592:     * This was removed due to problems with HTML processors.
 1593:     * See bug #345147.
 1594:     */
 1595:     /*
 1596:      * 4.8. Script and Style elements
 1597:      */
 1598:     if ((cur->type == XML_ELEMENT_NODE) &&
 1599: 	((xmlStrEqual(cur->name, BAD_CAST "script")) ||
 1600: 	 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
 1601: 	((cur->ns == NULL) ||
 1602: 	 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
 1603: 	xmlNodePtr child = cur->children;
 1604: 
 1605: 	while (child != NULL) {
 1606: 	    if (child->type == XML_TEXT_NODE) {
 1607: 		if ((xmlStrchr(child->content, '<') == NULL) &&
 1608: 		    (xmlStrchr(child->content, '&') == NULL) &&
 1609: 		    (xmlStrstr(child->content, BAD_CAST "]]>") == NULL)) {
 1610: 		    /* Nothing to escape, so just output as is... */
 1611: 		    /* FIXME: Should we do something about "--" also? */
 1612: 		    int level = ctxt->level;
 1613: 		    int indent = ctxt->format;
 1614: 
 1615: 		    ctxt->level = 0;
 1616: 		    ctxt->format = 0;
 1617: 		    xmlOutputBufferWriteString(buf, (const char *) child->content);
 1618: 		    /* (We cannot use xhtmlNodeDumpOutput() here because
 1619: 		     * we wish to leave '>' unescaped!) */
 1620: 		    ctxt->level = level;
 1621: 		    ctxt->format = indent;
 1622: 		} else {
 1623: 		    /* We must use a CDATA section.  Unfortunately,
 1624: 		     * this will break CSS and JavaScript when read by
 1625: 		     * a browser in HTML4-compliant mode. :-( */
 1626: 		    start = end = child->content;
 1627: 		    while (*end != '\0') {
 1628: 			if (*end == ']' &&
 1629: 			    *(end + 1) == ']' &&
 1630: 			    *(end + 2) == '>') {
 1631: 			    end = end + 2;
 1632: 			    xmlOutputBufferWrite(buf, 9, "<![CDATA[");
 1633: 			    xmlOutputBufferWrite(buf, end - start,
 1634: 						 (const char *)start);
 1635: 			    xmlOutputBufferWrite(buf, 3, "]]>");
 1636: 			    start = end;
 1637: 			}
 1638: 			end++;
 1639: 		    }
 1640: 		    if (start != end) {
 1641: 			xmlOutputBufferWrite(buf, 9, "<![CDATA[");
 1642: 			xmlOutputBufferWrite(buf, end - start,
 1643: 			                     (const char *)start);
 1644: 			xmlOutputBufferWrite(buf, 3, "]]>");
 1645: 		    }
 1646: 		}
 1647: 	    } else {
 1648: 		int level = ctxt->level;
 1649: 		int indent = ctxt->format;
 1650: 
 1651: 		ctxt->level = 0;
 1652: 		ctxt->format = 0;
 1653: 		xhtmlNodeDumpOutput(ctxt, child);
 1654: 		ctxt->level = level;
 1655: 		ctxt->format = indent;
 1656: 	    }
 1657: 	    child = child->next;
 1658: 	}
 1659:     }
 1660: #endif
 1661: 
 1662:     if (cur->children != NULL) {
 1663: 	int indent = ctxt->format;
 1664: 	
 1665: 	if (format == 1) xmlOutputBufferWrite(buf, 1, "\n");
 1666: 	if (ctxt->level >= 0) ctxt->level++;
 1667: 	ctxt->format = format;
 1668: 	xhtmlNodeListDumpOutput(ctxt, cur->children);
 1669: 	if (ctxt->level > 0) ctxt->level--;
 1670: 	ctxt->format = indent;
 1671: 	if ((xmlIndentTreeOutput) && (format == 1))
 1672: 	    xmlOutputBufferWrite(buf, ctxt->indent_size *
 1673: 	                         (ctxt->level > ctxt->indent_nr ? 
 1674: 				  ctxt->indent_nr : ctxt->level),
 1675: 				 ctxt->indent);
 1676:     }
 1677:     xmlOutputBufferWrite(buf, 2, "</");
 1678:     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
 1679:         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
 1680: 	xmlOutputBufferWrite(buf, 1, ":");
 1681:     }
 1682: 
 1683:     xmlOutputBufferWriteString(buf, (const char *)cur->name);
 1684:     xmlOutputBufferWrite(buf, 1, ">");
 1685: }
 1686: #endif
 1687: 
 1688: /************************************************************************
 1689:  *									*
 1690:  *			Public entry points				*
 1691:  *									*
 1692:  ************************************************************************/
 1693: 
 1694: /**
 1695:  * xmlSaveToFd:
 1696:  * @fd:  a file descriptor number
 1697:  * @encoding:  the encoding name to use or NULL
 1698:  * @options:  a set of xmlSaveOptions
 1699:  *
 1700:  * Create a document saving context serializing to a file descriptor
 1701:  * with the encoding and the options given.
 1702:  *
 1703:  * Returns a new serialization context or NULL in case of error.
 1704:  */
 1705: xmlSaveCtxtPtr
 1706: xmlSaveToFd(int fd, const char *encoding, int options)
 1707: {
 1708:     xmlSaveCtxtPtr ret;
 1709: 
 1710:     ret = xmlNewSaveCtxt(encoding, options);
 1711:     if (ret == NULL) return(NULL);
 1712:     ret->buf = xmlOutputBufferCreateFd(fd, ret->handler);
 1713:     if (ret->buf == NULL) {
 1714: 	xmlFreeSaveCtxt(ret);
 1715: 	return(NULL);
 1716:     }
 1717:     return(ret);
 1718: }
 1719: 
 1720: /**
 1721:  * xmlSaveToFilename:
 1722:  * @filename:  a file name or an URL
 1723:  * @encoding:  the encoding name to use or NULL
 1724:  * @options:  a set of xmlSaveOptions
 1725:  *
 1726:  * Create a document saving context serializing to a filename or possibly
 1727:  * to an URL (but this is less reliable) with the encoding and the options
 1728:  * given.
 1729:  *
 1730:  * Returns a new serialization context or NULL in case of error.
 1731:  */
 1732: xmlSaveCtxtPtr
 1733: xmlSaveToFilename(const char *filename, const char *encoding, int options)
 1734: {
 1735:     xmlSaveCtxtPtr ret;
 1736:     int compression = 0; /* TODO handle compression option */
 1737: 
 1738:     ret = xmlNewSaveCtxt(encoding, options);
 1739:     if (ret == NULL) return(NULL);
 1740:     ret->buf = xmlOutputBufferCreateFilename(filename, ret->handler,
 1741:                                              compression);
 1742:     if (ret->buf == NULL) {
 1743: 	xmlFreeSaveCtxt(ret);
 1744: 	return(NULL);
 1745:     }
 1746:     return(ret);
 1747: }
 1748: 
 1749: /**
 1750:  * xmlSaveToBuffer:
 1751:  * @buffer:  a buffer
 1752:  * @encoding:  the encoding name to use or NULL
 1753:  * @options:  a set of xmlSaveOptions
 1754:  *
 1755:  * Create a document saving context serializing to a buffer
 1756:  * with the encoding and the options given
 1757:  *
 1758:  * Returns a new serialization context or NULL in case of error.
 1759:  */
 1760: 
 1761: xmlSaveCtxtPtr
 1762: xmlSaveToBuffer(xmlBufferPtr buffer, const char *encoding, int options)
 1763: {
 1764:     xmlSaveCtxtPtr ret;
 1765:     xmlOutputBufferPtr out_buff;
 1766:     xmlCharEncodingHandlerPtr handler;
 1767: 
 1768:     ret = xmlNewSaveCtxt(encoding, options);
 1769:     if (ret == NULL) return(NULL);
 1770: 
 1771:     if (encoding != NULL) {
 1772:         handler = xmlFindCharEncodingHandler(encoding);
 1773:         if (handler == NULL) {
 1774:             xmlFree(ret);
 1775:             return(NULL);
 1776:         }
 1777:     } else
 1778:         handler = NULL;
 1779:     out_buff = xmlOutputBufferCreateBuffer(buffer, handler);
 1780:     if (out_buff == NULL) {
 1781:         xmlFree(ret);
 1782:         if (handler) xmlCharEncCloseFunc(handler);
 1783:         return(NULL);
 1784:     }
 1785: 
 1786:     ret->buf = out_buff;
 1787:     return(ret);
 1788: }
 1789: 
 1790: /**
 1791:  * xmlSaveToIO:
 1792:  * @iowrite:  an I/O write function
 1793:  * @ioclose:  an I/O close function
 1794:  * @ioctx:  an I/O handler
 1795:  * @encoding:  the encoding name to use or NULL
 1796:  * @options:  a set of xmlSaveOptions
 1797:  *
 1798:  * Create a document saving context serializing to a file descriptor
 1799:  * with the encoding and the options given
 1800:  *
 1801:  * Returns a new serialization context or NULL in case of error.
 1802:  */
 1803: xmlSaveCtxtPtr
 1804: xmlSaveToIO(xmlOutputWriteCallback iowrite,
 1805:             xmlOutputCloseCallback ioclose,
 1806:             void *ioctx, const char *encoding, int options)
 1807: {
 1808:     xmlSaveCtxtPtr ret;
 1809: 
 1810:     ret = xmlNewSaveCtxt(encoding, options);
 1811:     if (ret == NULL) return(NULL);
 1812:     ret->buf = xmlOutputBufferCreateIO(iowrite, ioclose, ioctx, ret->handler);
 1813:     if (ret->buf == NULL) {
 1814: 	xmlFreeSaveCtxt(ret);
 1815: 	return(NULL);
 1816:     }
 1817:     return(ret);
 1818: }
 1819: 
 1820: /**
 1821:  * xmlSaveDoc:
 1822:  * @ctxt:  a document saving context
 1823:  * @doc:  a document
 1824:  *
 1825:  * Save a full document to a saving context
 1826:  * TODO: The function is not fully implemented yet as it does not return the
 1827:  * byte count but 0 instead
 1828:  *
 1829:  * Returns the number of byte written or -1 in case of error
 1830:  */
 1831: long
 1832: xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc)
 1833: {
 1834:     long ret = 0;
 1835: 
 1836:     if ((ctxt == NULL) || (doc == NULL)) return(-1);
 1837:     if (xmlDocContentDumpOutput(ctxt, doc) < 0)
 1838:         return(-1);
 1839:     return(ret);
 1840: }
 1841: 
 1842: /**
 1843:  * xmlSaveTree:
 1844:  * @ctxt:  a document saving context
 1845:  * @node:  the top node of the subtree to save
 1846:  *
 1847:  * Save a subtree starting at the node parameter to a saving context
 1848:  * TODO: The function is not fully implemented yet as it does not return the
 1849:  * byte count but 0 instead
 1850:  *
 1851:  * Returns the number of byte written or -1 in case of error
 1852:  */
 1853: long
 1854: xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr node)
 1855: {
 1856:     long ret = 0;
 1857: 
 1858:     if ((ctxt == NULL) || (node == NULL)) return(-1);
 1859:     xmlNodeDumpOutputInternal(ctxt, node);
 1860:     return(ret);
 1861: }
 1862: 
 1863: /**
 1864:  * xmlSaveFlush:
 1865:  * @ctxt:  a document saving context
 1866:  *
 1867:  * Flush a document saving context, i.e. make sure that all bytes have
 1868:  * been output.
 1869:  *
 1870:  * Returns the number of byte written or -1 in case of error.
 1871:  */
 1872: int
 1873: xmlSaveFlush(xmlSaveCtxtPtr ctxt)
 1874: {
 1875:     if (ctxt == NULL) return(-1);
 1876:     if (ctxt->buf == NULL) return(-1);
 1877:     return(xmlOutputBufferFlush(ctxt->buf));
 1878: }
 1879: 
 1880: /**
 1881:  * xmlSaveClose:
 1882:  * @ctxt:  a document saving context
 1883:  *
 1884:  * Close a document saving context, i.e. make sure that all bytes have
 1885:  * been output and free the associated data.
 1886:  *
 1887:  * Returns the number of byte written or -1 in case of error.
 1888:  */
 1889: int
 1890: xmlSaveClose(xmlSaveCtxtPtr ctxt)
 1891: {
 1892:     int ret;
 1893: 
 1894:     if (ctxt == NULL) return(-1);
 1895:     ret = xmlSaveFlush(ctxt);
 1896:     xmlFreeSaveCtxt(ctxt);
 1897:     return(ret);
 1898: }
 1899: 
 1900: /**
 1901:  * xmlSaveSetEscape:
 1902:  * @ctxt:  a document saving context
 1903:  * @escape:  the escaping function
 1904:  *
 1905:  * Set a custom escaping function to be used for text in element content
 1906:  *
 1907:  * Returns 0 if successful or -1 in case of error.
 1908:  */
 1909: int
 1910: xmlSaveSetEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
 1911: {
 1912:     if (ctxt == NULL) return(-1);
 1913:     ctxt->escape = escape;
 1914:     return(0);
 1915: }
 1916: 
 1917: /**
 1918:  * xmlSaveSetAttrEscape:
 1919:  * @ctxt:  a document saving context
 1920:  * @escape:  the escaping function
 1921:  *
 1922:  * Set a custom escaping function to be used for text in attribute content
 1923:  *
 1924:  * Returns 0 if successful or -1 in case of error.
 1925:  */
 1926: int
 1927: xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
 1928: {
 1929:     if (ctxt == NULL) return(-1);
 1930:     ctxt->escapeAttr = escape;
 1931:     return(0);
 1932: }
 1933: 
 1934: /************************************************************************
 1935:  *									*
 1936:  *		Public entry points based on buffers			*
 1937:  *									*
 1938:  ************************************************************************/
 1939: /**
 1940:  * xmlAttrSerializeTxtContent:
 1941:  * @buf:  the XML buffer output
 1942:  * @doc:  the document
 1943:  * @attr: the attribute node
 1944:  * @string: the text content
 1945:  *
 1946:  * Serialize text attribute values to an xml simple buffer
 1947:  */
 1948: void
 1949: xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc,
 1950:                            xmlAttrPtr attr, const xmlChar * string)
 1951: {
 1952:     xmlChar *base, *cur;
 1953: 
 1954:     if (string == NULL)
 1955:         return;
 1956:     base = cur = (xmlChar *) string;
 1957:     while (*cur != 0) {
 1958:         if (*cur == '\n') {
 1959:             if (base != cur)
 1960:                 xmlBufferAdd(buf, base, cur - base);
 1961:             xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
 1962:             cur++;
 1963:             base = cur;
 1964:         } else if (*cur == '\r') {
 1965:             if (base != cur)
 1966:                 xmlBufferAdd(buf, base, cur - base);
 1967:             xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
 1968:             cur++;
 1969:             base = cur;
 1970:         } else if (*cur == '\t') {
 1971:             if (base != cur)
 1972:                 xmlBufferAdd(buf, base, cur - base);
 1973:             xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
 1974:             cur++;
 1975:             base = cur;
 1976:         } else if (*cur == '"') {
 1977:             if (base != cur)
 1978:                 xmlBufferAdd(buf, base, cur - base);
 1979:             xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
 1980:             cur++;
 1981:             base = cur;
 1982:         } else if (*cur == '<') {
 1983:             if (base != cur)
 1984:                 xmlBufferAdd(buf, base, cur - base);
 1985:             xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
 1986:             cur++;
 1987:             base = cur;
 1988:         } else if (*cur == '>') {
 1989:             if (base != cur)
 1990:                 xmlBufferAdd(buf, base, cur - base);
 1991:             xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
 1992:             cur++;
 1993:             base = cur;
 1994:         } else if (*cur == '&') {
 1995:             if (base != cur)
 1996:                 xmlBufferAdd(buf, base, cur - base);
 1997:             xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
 1998:             cur++;
 1999:             base = cur;
 2000:         } else if ((*cur >= 0x80) && ((doc == NULL) ||
 2001:                                       (doc->encoding == NULL))) {
 2002:             /*
 2003:              * We assume we have UTF-8 content.
 2004:              */
 2005:             unsigned char tmp[12];
 2006:             int val = 0, l = 1;
 2007: 
 2008:             if (base != cur)
 2009:                 xmlBufferAdd(buf, base, cur - base);
 2010:             if (*cur < 0xC0) {
 2011:                 xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL);
 2012:                 if (doc != NULL)
 2013:                     doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
 2014: 		xmlSerializeHexCharRef(tmp, *cur);
 2015:                 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
 2016:                 cur++;
 2017:                 base = cur;
 2018:                 continue;
 2019:             } else if (*cur < 0xE0) {
 2020:                 val = (cur[0]) & 0x1F;
 2021:                 val <<= 6;
 2022:                 val |= (cur[1]) & 0x3F;
 2023:                 l = 2;
 2024:             } else if (*cur < 0xF0) {
 2025:                 val = (cur[0]) & 0x0F;
 2026:                 val <<= 6;
 2027:                 val |= (cur[1]) & 0x3F;
 2028:                 val <<= 6;
 2029:                 val |= (cur[2]) & 0x3F;
 2030:                 l = 3;
 2031:             } else if (*cur < 0xF8) {
 2032:                 val = (cur[0]) & 0x07;
 2033:                 val <<= 6;
 2034:                 val |= (cur[1]) & 0x3F;
 2035:                 val <<= 6;
 2036:                 val |= (cur[2]) & 0x3F;
 2037:                 val <<= 6;
 2038:                 val |= (cur[3]) & 0x3F;
 2039:                 l = 4;
 2040:             }
 2041:             if ((l == 1) || (!IS_CHAR(val))) {
 2042:                 xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL);
 2043:                 if (doc != NULL)
 2044:                     doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
 2045: 		
 2046: 		xmlSerializeHexCharRef(tmp, *cur);
 2047:                 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
 2048:                 cur++;
 2049:                 base = cur;
 2050:                 continue;
 2051:             }
 2052:             /*
 2053:              * We could do multiple things here. Just save
 2054:              * as a char ref
 2055:              */
 2056: 	    xmlSerializeHexCharRef(tmp, val);
 2057:             xmlBufferAdd(buf, (xmlChar *) tmp, -1);
 2058:             cur += l;
 2059:             base = cur;
 2060:         } else {
 2061:             cur++;
 2062:         }
 2063:     }
 2064:     if (base != cur)
 2065:         xmlBufferAdd(buf, base, cur - base);
 2066: }
 2067: 
 2068: /**
 2069:  * xmlNodeDump:
 2070:  * @buf:  the XML buffer output
 2071:  * @doc:  the document
 2072:  * @cur:  the current node
 2073:  * @level: the imbrication level for indenting
 2074:  * @format: is formatting allowed
 2075:  *
 2076:  * Dump an XML node, recursive behaviour,children are printed too.
 2077:  * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
 2078:  * or xmlKeepBlanksDefault(0) was called
 2079:  *
 2080:  * Returns the number of bytes written to the buffer or -1 in case of error
 2081:  */
 2082: int
 2083: xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
 2084:             int format)
 2085: {
 2086:     unsigned int use;
 2087:     int ret;
 2088:     xmlOutputBufferPtr outbuf;
 2089: 
 2090:     xmlInitParser();
 2091: 
 2092:     if (cur == NULL) {
 2093: #ifdef DEBUG_TREE
 2094:         xmlGenericError(xmlGenericErrorContext,
 2095:                         "xmlNodeDump : node == NULL\n");
 2096: #endif
 2097:         return (-1);
 2098:     }
 2099:     if (buf == NULL) {
 2100: #ifdef DEBUG_TREE
 2101:         xmlGenericError(xmlGenericErrorContext,
 2102:                         "xmlNodeDump : buf == NULL\n");
 2103: #endif
 2104:         return (-1);
 2105:     }
 2106:     outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
 2107:     if (outbuf == NULL) {
 2108:         xmlSaveErrMemory("creating buffer");
 2109:         return (-1);
 2110:     }
 2111:     memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
 2112:     outbuf->buffer = buf;
 2113:     outbuf->encoder = NULL;
 2114:     outbuf->writecallback = NULL;
 2115:     outbuf->closecallback = NULL;
 2116:     outbuf->context = NULL;
 2117:     outbuf->written = 0;
 2118: 
 2119:     use = buf->use;
 2120:     xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
 2121:     xmlFree(outbuf);
 2122:     ret = buf->use - use;
 2123:     return (ret);
 2124: }
 2125: 
 2126: /**
 2127:  * xmlElemDump:
 2128:  * @f:  the FILE * for the output
 2129:  * @doc:  the document
 2130:  * @cur:  the current node
 2131:  *
 2132:  * Dump an XML/HTML node, recursive behaviour, children are printed too.
 2133:  */
 2134: void
 2135: xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
 2136: {
 2137:     xmlOutputBufferPtr outbuf;
 2138: 
 2139:     xmlInitParser();
 2140: 
 2141:     if (cur == NULL) {
 2142: #ifdef DEBUG_TREE
 2143:         xmlGenericError(xmlGenericErrorContext,
 2144:                         "xmlElemDump : cur == NULL\n");
 2145: #endif
 2146:         return;
 2147:     }
 2148: #ifdef DEBUG_TREE
 2149:     if (doc == NULL) {
 2150:         xmlGenericError(xmlGenericErrorContext,
 2151:                         "xmlElemDump : doc == NULL\n");
 2152:     }
 2153: #endif
 2154: 
 2155:     outbuf = xmlOutputBufferCreateFile(f, NULL);
 2156:     if (outbuf == NULL)
 2157:         return;
 2158:     if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
 2159: #ifdef LIBXML_HTML_ENABLED
 2160:         htmlNodeDumpOutput(outbuf, doc, cur, NULL);
 2161: #else
 2162: 	xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");
 2163: #endif /* LIBXML_HTML_ENABLED */
 2164:     } else
 2165:         xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
 2166:     xmlOutputBufferClose(outbuf);
 2167: }
 2168: 
 2169: /************************************************************************
 2170:  *									*
 2171:  *		Saving functions front-ends				*
 2172:  *									*
 2173:  ************************************************************************/
 2174: 
 2175: /**
 2176:  * xmlNodeDumpOutput:
 2177:  * @buf:  the XML buffer output
 2178:  * @doc:  the document
 2179:  * @cur:  the current node
 2180:  * @level: the imbrication level for indenting
 2181:  * @format: is formatting allowed
 2182:  * @encoding:  an optional encoding string
 2183:  *
 2184:  * Dump an XML node, recursive behaviour, children are printed too.
 2185:  * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
 2186:  * or xmlKeepBlanksDefault(0) was called
 2187:  */
 2188: void
 2189: xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
 2190:                   int level, int format, const char *encoding)
 2191: {
 2192:     xmlSaveCtxt ctxt;
 2193: #ifdef LIBXML_HTML_ENABLED
 2194:     xmlDtdPtr dtd;
 2195:     int is_xhtml = 0;
 2196: #endif
 2197: 
 2198:     xmlInitParser();
 2199: 
 2200:     if ((buf == NULL) || (cur == NULL)) return;
 2201: 
 2202:     if (encoding == NULL)
 2203:         encoding = "UTF-8";
 2204: 
 2205:     memset(&ctxt, 0, sizeof(ctxt));
 2206:     ctxt.doc = doc;
 2207:     ctxt.buf = buf;
 2208:     ctxt.level = level;
 2209:     ctxt.format = format ? 1 : 0;
 2210:     ctxt.encoding = (const xmlChar *) encoding;
 2211:     xmlSaveCtxtInit(&ctxt);
 2212:     ctxt.options |= XML_SAVE_AS_XML;
 2213: 
 2214: #ifdef LIBXML_HTML_ENABLED
 2215:     dtd = xmlGetIntSubset(doc);
 2216:     if (dtd != NULL) {
 2217: 	is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
 2218: 	if (is_xhtml < 0)
 2219: 	    is_xhtml = 0;
 2220:     }
 2221: 
 2222:     if (is_xhtml)
 2223:         xhtmlNodeDumpOutput(&ctxt, cur);
 2224:     else
 2225: #endif
 2226:         xmlNodeDumpOutputInternal(&ctxt, cur);
 2227: }
 2228: 
 2229: /**
 2230:  * xmlDocDumpFormatMemoryEnc:
 2231:  * @out_doc:  Document to generate XML text from
 2232:  * @doc_txt_ptr:  Memory pointer for allocated XML text
 2233:  * @doc_txt_len:  Length of the generated XML text
 2234:  * @txt_encoding:  Character encoding to use when generating XML text
 2235:  * @format:  should formatting spaces been added
 2236:  *
 2237:  * Dump the current DOM tree into memory using the character encoding specified
 2238:  * by the caller.  Note it is up to the caller of this function to free the
 2239:  * allocated memory with xmlFree().
 2240:  * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
 2241:  * or xmlKeepBlanksDefault(0) was called
 2242:  */
 2243: 
 2244: void
 2245: xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
 2246: 		int * doc_txt_len, const char * txt_encoding,
 2247: 		int format) {
 2248:     xmlSaveCtxt ctxt;
 2249:     int                         dummy = 0;
 2250:     xmlOutputBufferPtr          out_buff = NULL;
 2251:     xmlCharEncodingHandlerPtr   conv_hdlr = NULL;
 2252: 
 2253:     if (doc_txt_len == NULL) {
 2254:         doc_txt_len = &dummy;   /*  Continue, caller just won't get length */
 2255:     }
 2256: 
 2257:     if (doc_txt_ptr == NULL) {
 2258:         *doc_txt_len = 0;
 2259:         return;
 2260:     }
 2261: 
 2262:     *doc_txt_ptr = NULL;
 2263:     *doc_txt_len = 0;
 2264: 
 2265:     if (out_doc == NULL) {
 2266:         /*  No document, no output  */
 2267:         return;
 2268:     }
 2269: 
 2270:     /*
 2271:      *  Validate the encoding value, if provided.
 2272:      *  This logic is copied from xmlSaveFileEnc.
 2273:      */
 2274: 
 2275:     if (txt_encoding == NULL)
 2276: 	txt_encoding = (const char *) out_doc->encoding;
 2277:     if (txt_encoding != NULL) {
 2278: 	conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
 2279: 	if ( conv_hdlr == NULL ) {
 2280: 	    xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
 2281: 		       txt_encoding);
 2282: 	    return;
 2283: 	}
 2284:     }
 2285: 
 2286:     if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
 2287:         xmlSaveErrMemory("creating buffer");
 2288:         return;
 2289:     }
 2290: 
 2291:     memset(&ctxt, 0, sizeof(ctxt));
 2292:     ctxt.doc = out_doc;
 2293:     ctxt.buf = out_buff;
 2294:     ctxt.level = 0;
 2295:     ctxt.format = format ? 1 : 0;
 2296:     ctxt.encoding = (const xmlChar *) txt_encoding;
 2297:     xmlSaveCtxtInit(&ctxt);
 2298:     ctxt.options |= XML_SAVE_AS_XML;
 2299:     xmlDocContentDumpOutput(&ctxt, out_doc);
 2300:     xmlOutputBufferFlush(out_buff);
 2301:     if (out_buff->conv != NULL) {
 2302: 	*doc_txt_len = out_buff->conv->use;
 2303: 	*doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
 2304:     } else {
 2305: 	*doc_txt_len = out_buff->buffer->use;
 2306: 	*doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
 2307:     }
 2308:     (void)xmlOutputBufferClose(out_buff);
 2309: 
 2310:     if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
 2311:         *doc_txt_len = 0;
 2312:         xmlSaveErrMemory("creating output");
 2313:     }
 2314: 
 2315:     return;
 2316: }
 2317: 
 2318: /**
 2319:  * xmlDocDumpMemory:
 2320:  * @cur:  the document
 2321:  * @mem:  OUT: the memory pointer
 2322:  * @size:  OUT: the memory length
 2323:  *
 2324:  * Dump an XML document in memory and return the #xmlChar * and it's size
 2325:  * in bytes. It's up to the caller to free the memory with xmlFree().
 2326:  * The resulting byte array is zero terminated, though the last 0 is not
 2327:  * included in the returned size.
 2328:  */
 2329: void
 2330: xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
 2331:     xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
 2332: }
 2333: 
 2334: /**
 2335:  * xmlDocDumpFormatMemory:
 2336:  * @cur:  the document
 2337:  * @mem:  OUT: the memory pointer
 2338:  * @size:  OUT: the memory length
 2339:  * @format:  should formatting spaces been added
 2340:  *
 2341:  *
 2342:  * Dump an XML document in memory and return the #xmlChar * and it's size.
 2343:  * It's up to the caller to free the memory with xmlFree().
 2344:  * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
 2345:  * or xmlKeepBlanksDefault(0) was called
 2346:  */
 2347: void
 2348: xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
 2349:     xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
 2350: }
 2351: 
 2352: /**
 2353:  * xmlDocDumpMemoryEnc:
 2354:  * @out_doc:  Document to generate XML text from
 2355:  * @doc_txt_ptr:  Memory pointer for allocated XML text
 2356:  * @doc_txt_len:  Length of the generated XML text
 2357:  * @txt_encoding:  Character encoding to use when generating XML text
 2358:  *
 2359:  * Dump the current DOM tree into memory using the character encoding specified
 2360:  * by the caller.  Note it is up to the caller of this function to free the
 2361:  * allocated memory with xmlFree().
 2362:  */
 2363: 
 2364: void
 2365: xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
 2366: 	            int * doc_txt_len, const char * txt_encoding) {
 2367:     xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
 2368: 	                      txt_encoding, 0);
 2369: }
 2370: 
 2371: /**
 2372:  * xmlDocFormatDump:
 2373:  * @f:  the FILE*
 2374:  * @cur:  the document
 2375:  * @format: should formatting spaces been added
 2376:  *
 2377:  * Dump an XML document to an open FILE.
 2378:  *
 2379:  * returns: the number of bytes written or -1 in case of failure.
 2380:  * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
 2381:  * or xmlKeepBlanksDefault(0) was called
 2382:  */
 2383: int
 2384: xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
 2385:     xmlSaveCtxt ctxt;
 2386:     xmlOutputBufferPtr buf;
 2387:     const char * encoding;
 2388:     xmlCharEncodingHandlerPtr handler = NULL;
 2389:     int ret;
 2390: 
 2391:     if (cur == NULL) {
 2392: #ifdef DEBUG_TREE
 2393:         xmlGenericError(xmlGenericErrorContext,
 2394: 		"xmlDocDump : document == NULL\n");
 2395: #endif
 2396: 	return(-1);
 2397:     }
 2398:     encoding = (const char *) cur->encoding;
 2399: 
 2400:     if (encoding != NULL) {
 2401: 	handler = xmlFindCharEncodingHandler(encoding);
 2402: 	if (handler == NULL) {
 2403: 	    xmlFree((char *) cur->encoding);
 2404: 	    cur->encoding = NULL;
 2405: 	    encoding = NULL;
 2406: 	}
 2407:     }
 2408:     buf = xmlOutputBufferCreateFile(f, handler);
 2409:     if (buf == NULL) return(-1);
 2410:     memset(&ctxt, 0, sizeof(ctxt));
 2411:     ctxt.doc = cur;
 2412:     ctxt.buf = buf;
 2413:     ctxt.level = 0;
 2414:     ctxt.format = format ? 1 : 0;
 2415:     ctxt.encoding = (const xmlChar *) encoding;
 2416:     xmlSaveCtxtInit(&ctxt);
 2417:     ctxt.options |= XML_SAVE_AS_XML;
 2418:     xmlDocContentDumpOutput(&ctxt, cur);
 2419: 
 2420:     ret = xmlOutputBufferClose(buf);
 2421:     return(ret);
 2422: }
 2423: 
 2424: /**
 2425:  * xmlDocDump:
 2426:  * @f:  the FILE*
 2427:  * @cur:  the document
 2428:  *
 2429:  * Dump an XML document to an open FILE.
 2430:  *
 2431:  * returns: the number of bytes written or -1 in case of failure.
 2432:  */
 2433: int
 2434: xmlDocDump(FILE *f, xmlDocPtr cur) {
 2435:     return(xmlDocFormatDump (f, cur, 0));
 2436: }
 2437: 
 2438: /**
 2439:  * xmlSaveFileTo:
 2440:  * @buf:  an output I/O buffer
 2441:  * @cur:  the document
 2442:  * @encoding:  the encoding if any assuming the I/O layer handles the trancoding
 2443:  *
 2444:  * Dump an XML document to an I/O buffer.
 2445:  * Warning ! This call xmlOutputBufferClose() on buf which is not available
 2446:  * after this call.
 2447:  *
 2448:  * returns: the number of bytes written or -1 in case of failure.
 2449:  */
 2450: int
 2451: xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
 2452:     xmlSaveCtxt ctxt;
 2453:     int ret;
 2454: 
 2455:     if (buf == NULL) return(-1);
 2456:     if (cur == NULL) {
 2457:         xmlOutputBufferClose(buf);
 2458: 	return(-1);
 2459:     }
 2460:     memset(&ctxt, 0, sizeof(ctxt));
 2461:     ctxt.doc = cur;
 2462:     ctxt.buf = buf;
 2463:     ctxt.level = 0;
 2464:     ctxt.format = 0;
 2465:     ctxt.encoding = (const xmlChar *) encoding;
 2466:     xmlSaveCtxtInit(&ctxt);
 2467:     ctxt.options |= XML_SAVE_AS_XML;
 2468:     xmlDocContentDumpOutput(&ctxt, cur);
 2469:     ret = xmlOutputBufferClose(buf);
 2470:     return(ret);
 2471: }
 2472: 
 2473: /**
 2474:  * xmlSaveFormatFileTo:
 2475:  * @buf:  an output I/O buffer
 2476:  * @cur:  the document
 2477:  * @encoding:  the encoding if any assuming the I/O layer handles the trancoding
 2478:  * @format: should formatting spaces been added
 2479:  *
 2480:  * Dump an XML document to an I/O buffer.
 2481:  * Warning ! This call xmlOutputBufferClose() on buf which is not available
 2482:  * after this call.
 2483:  *
 2484:  * returns: the number of bytes written or -1 in case of failure.
 2485:  */
 2486: int
 2487: xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur,
 2488:                     const char *encoding, int format)
 2489: {
 2490:     xmlSaveCtxt ctxt;
 2491:     int ret;
 2492: 
 2493:     if (buf == NULL) return(-1);
 2494:     if ((cur == NULL) ||
 2495:         ((cur->type != XML_DOCUMENT_NODE) &&
 2496: 	 (cur->type != XML_HTML_DOCUMENT_NODE))) {
 2497:         xmlOutputBufferClose(buf);
 2498: 	return(-1);
 2499:     }
 2500:     memset(&ctxt, 0, sizeof(ctxt));
 2501:     ctxt.doc = cur;
 2502:     ctxt.buf = buf;
 2503:     ctxt.level = 0;
 2504:     ctxt.format = format ? 1 : 0;
 2505:     ctxt.encoding = (const xmlChar *) encoding;
 2506:     xmlSaveCtxtInit(&ctxt);
 2507:     ctxt.options |= XML_SAVE_AS_XML;
 2508:     xmlDocContentDumpOutput(&ctxt, cur);
 2509:     ret = xmlOutputBufferClose(buf);
 2510:     return (ret);
 2511: }
 2512: 
 2513: /**
 2514:  * xmlSaveFormatFileEnc:
 2515:  * @filename:  the filename or URL to output
 2516:  * @cur:  the document being saved
 2517:  * @encoding:  the name of the encoding to use or NULL.
 2518:  * @format:  should formatting spaces be added.
 2519:  *
 2520:  * Dump an XML document to a file or an URL.
 2521:  *
 2522:  * Returns the number of bytes written or -1 in case of error.
 2523:  * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
 2524:  * or xmlKeepBlanksDefault(0) was called
 2525:  */
 2526: int
 2527: xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
 2528: 			const char * encoding, int format ) {
 2529:     xmlSaveCtxt ctxt;
 2530:     xmlOutputBufferPtr buf;
 2531:     xmlCharEncodingHandlerPtr handler = NULL;
 2532:     int ret;
 2533: 
 2534:     if (cur == NULL)
 2535: 	return(-1);
 2536: 
 2537:     if (encoding == NULL)
 2538: 	encoding = (const char *) cur->encoding;
 2539: 
 2540:     if (encoding != NULL) {
 2541: 
 2542: 	    handler = xmlFindCharEncodingHandler(encoding);
 2543: 	    if (handler == NULL)
 2544: 		return(-1);
 2545:     }
 2546: 
 2547: #ifdef HAVE_ZLIB_H
 2548:     if (cur->compression < 0) cur->compression = xmlGetCompressMode();
 2549: #endif
 2550:     /* 
 2551:      * save the content to a temp buffer.
 2552:      */
 2553:     buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
 2554:     if (buf == NULL) return(-1);
 2555:     memset(&ctxt, 0, sizeof(ctxt));
 2556:     ctxt.doc = cur;
 2557:     ctxt.buf = buf;
 2558:     ctxt.level = 0;
 2559:     ctxt.format = format ? 1 : 0;
 2560:     ctxt.encoding = (const xmlChar *) encoding;
 2561:     xmlSaveCtxtInit(&ctxt);
 2562:     ctxt.options |= XML_SAVE_AS_XML;
 2563: 
 2564:     xmlDocContentDumpOutput(&ctxt, cur);
 2565: 
 2566:     ret = xmlOutputBufferClose(buf);
 2567:     return(ret);
 2568: }
 2569: 
 2570: 
 2571: /**
 2572:  * xmlSaveFileEnc:
 2573:  * @filename:  the filename (or URL)
 2574:  * @cur:  the document
 2575:  * @encoding:  the name of an encoding (or NULL)
 2576:  *
 2577:  * Dump an XML document, converting it to the given encoding
 2578:  *
 2579:  * returns: the number of bytes written or -1 in case of failure.
 2580:  */
 2581: int
 2582: xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
 2583:     return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
 2584: }
 2585: 
 2586: /**
 2587:  * xmlSaveFormatFile:
 2588:  * @filename:  the filename (or URL)
 2589:  * @cur:  the document
 2590:  * @format:  should formatting spaces been added
 2591:  *
 2592:  * Dump an XML document to a file. Will use compression if
 2593:  * compiled in and enabled. If @filename is "-" the stdout file is
 2594:  * used. If @format is set then the document will be indented on output.
 2595:  * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
 2596:  * or xmlKeepBlanksDefault(0) was called
 2597:  *
 2598:  * returns: the number of bytes written or -1 in case of failure.
 2599:  */
 2600: int
 2601: xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
 2602:     return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
 2603: }
 2604: 
 2605: /**
 2606:  * xmlSaveFile:
 2607:  * @filename:  the filename (or URL)
 2608:  * @cur:  the document
 2609:  *
 2610:  * Dump an XML document to a file. Will use compression if
 2611:  * compiled in and enabled. If @filename is "-" the stdout file is
 2612:  * used.
 2613:  * returns: the number of bytes written or -1 in case of failure.
 2614:  */
 2615: int
 2616: xmlSaveFile(const char *filename, xmlDocPtr cur) {
 2617:     return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
 2618: }
 2619: 
 2620: #endif /* LIBXML_OUTPUT_ENABLED */
 2621: 
 2622: #define bottom_xmlsave
 2623: #include "elfgcchack.h"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>