wined3d: Respect the BO memory offset in wined3d_context_gl_map_bo_address().
[wine.git] / libs / xml2 / xmlsave.c
blob61a40459bd2df16ef33fbbbc349ef4cc0f3bd005
1 /*
2 * xmlsave.c: Implementation of the document serializer
4 * See Copyright for the status of this software.
6 * daniel@veillard.com
7 */
9 #define IN_LIBXML
10 #include "libxml.h"
12 #include <string.h>
13 #include <libxml/xmlmemory.h>
14 #include <libxml/parserInternals.h>
15 #include <libxml/tree.h>
16 #include <libxml/xmlsave.h>
18 #define MAX_INDENT 60
20 #include <libxml/HTMLtree.h>
22 #include "buf.h"
23 #include "enc.h"
24 #include "save.h"
26 /************************************************************************
27 * *
28 * XHTML detection *
29 * *
30 ************************************************************************/
31 #define XHTML_STRICT_PUBLIC_ID BAD_CAST \
32 "-//W3C//DTD XHTML 1.0 Strict//EN"
33 #define XHTML_STRICT_SYSTEM_ID BAD_CAST \
34 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
35 #define XHTML_FRAME_PUBLIC_ID BAD_CAST \
36 "-//W3C//DTD XHTML 1.0 Frameset//EN"
37 #define XHTML_FRAME_SYSTEM_ID BAD_CAST \
38 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
39 #define XHTML_TRANS_PUBLIC_ID BAD_CAST \
40 "-//W3C//DTD XHTML 1.0 Transitional//EN"
41 #define XHTML_TRANS_SYSTEM_ID BAD_CAST \
42 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
44 #define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
45 /**
46 * xmlIsXHTML:
47 * @systemID: the system identifier
48 * @publicID: the public identifier
50 * Try to find if the document correspond to an XHTML DTD
52 * Returns 1 if true, 0 if not and -1 in case of error
54 int
55 xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
56 if ((systemID == NULL) && (publicID == NULL))
57 return(-1);
58 if (publicID != NULL) {
59 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
60 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
61 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
63 if (systemID != NULL) {
64 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
65 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
66 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
68 return(0);
71 #ifdef LIBXML_OUTPUT_ENABLED
73 #define TODO \
74 xmlGenericError(xmlGenericErrorContext, \
75 "Unimplemented block at %s:%d\n", \
76 __FILE__, __LINE__);
78 struct _xmlSaveCtxt {
79 void *_private;
80 int type;
81 int fd;
82 const xmlChar *filename;
83 const xmlChar *encoding;
84 xmlCharEncodingHandlerPtr handler;
85 xmlOutputBufferPtr buf;
86 int options;
87 int level;
88 int format;
89 char indent[MAX_INDENT + 1]; /* array for indenting output */
90 int indent_nr;
91 int indent_size;
92 xmlCharEncodingOutputFunc escape; /* used for element content */
93 xmlCharEncodingOutputFunc escapeAttr;/* used for attribute content */
96 /************************************************************************
97 * *
98 * Output error handlers *
99 * *
100 ************************************************************************/
102 * xmlSaveErrMemory:
103 * @extra: extra information
105 * Handle an out of memory condition
107 static void
108 xmlSaveErrMemory(const char *extra)
110 __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
114 * xmlSaveErr:
115 * @code: the error number
116 * @node: the location of the error.
117 * @extra: extra information
119 * Handle an out of memory condition
121 static void
122 xmlSaveErr(int code, xmlNodePtr node, const char *extra)
124 const char *msg = NULL;
126 switch(code) {
127 case XML_SAVE_NOT_UTF8:
128 msg = "string is not in UTF-8\n";
129 break;
130 case XML_SAVE_CHAR_INVALID:
131 msg = "invalid character value\n";
132 break;
133 case XML_SAVE_UNKNOWN_ENCODING:
134 msg = "unknown encoding %s\n";
135 break;
136 case XML_SAVE_NO_DOCTYPE:
137 msg = "document has no DOCTYPE\n";
138 break;
139 default:
140 msg = "unexpected error number\n";
142 __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
145 /************************************************************************
147 * Special escaping routines *
149 ************************************************************************/
150 static unsigned char *
151 xmlSerializeHexCharRef(unsigned char *out, int val) {
152 unsigned char *ptr;
154 *out++ = '&';
155 *out++ = '#';
156 *out++ = 'x';
157 if (val < 0x10) ptr = out;
158 else if (val < 0x100) ptr = out + 1;
159 else if (val < 0x1000) ptr = out + 2;
160 else if (val < 0x10000) ptr = out + 3;
161 else if (val < 0x100000) ptr = out + 4;
162 else ptr = out + 5;
163 out = ptr + 1;
164 while (val > 0) {
165 switch (val & 0xF) {
166 case 0: *ptr-- = '0'; break;
167 case 1: *ptr-- = '1'; break;
168 case 2: *ptr-- = '2'; break;
169 case 3: *ptr-- = '3'; break;
170 case 4: *ptr-- = '4'; break;
171 case 5: *ptr-- = '5'; break;
172 case 6: *ptr-- = '6'; break;
173 case 7: *ptr-- = '7'; break;
174 case 8: *ptr-- = '8'; break;
175 case 9: *ptr-- = '9'; break;
176 case 0xA: *ptr-- = 'A'; break;
177 case 0xB: *ptr-- = 'B'; break;
178 case 0xC: *ptr-- = 'C'; break;
179 case 0xD: *ptr-- = 'D'; break;
180 case 0xE: *ptr-- = 'E'; break;
181 case 0xF: *ptr-- = 'F'; break;
182 default: *ptr-- = '0'; break;
184 val >>= 4;
186 *out++ = ';';
187 *out = 0;
188 return(out);
192 * xmlEscapeEntities:
193 * @out: a pointer to an array of bytes to store the result
194 * @outlen: the length of @out
195 * @in: a pointer to an array of unescaped UTF-8 bytes
196 * @inlen: the length of @in
198 * Take a block of UTF-8 chars in and escape them. Used when there is no
199 * encoding specified.
201 * Returns 0 if success, or -1 otherwise
202 * The value of @inlen after return is the number of octets consumed
203 * if the return value is positive, else unpredictable.
204 * The value of @outlen after return is the number of octets consumed.
206 static int
207 xmlEscapeEntities(unsigned char* out, int *outlen,
208 const xmlChar* in, int *inlen) {
209 unsigned char* outstart = out;
210 const unsigned char* base = in;
211 unsigned char* outend = out + *outlen;
212 const unsigned char* inend;
213 int val;
215 inend = in + (*inlen);
217 while ((in < inend) && (out < outend)) {
218 if (*in == '<') {
219 if (outend - out < 4) break;
220 *out++ = '&';
221 *out++ = 'l';
222 *out++ = 't';
223 *out++ = ';';
224 in++;
225 continue;
226 } else if (*in == '>') {
227 if (outend - out < 4) break;
228 *out++ = '&';
229 *out++ = 'g';
230 *out++ = 't';
231 *out++ = ';';
232 in++;
233 continue;
234 } else if (*in == '&') {
235 if (outend - out < 5) break;
236 *out++ = '&';
237 *out++ = 'a';
238 *out++ = 'm';
239 *out++ = 'p';
240 *out++ = ';';
241 in++;
242 continue;
243 } else if (((*in >= 0x20) && (*in < 0x80)) ||
244 (*in == '\n') || (*in == '\t')) {
246 * default case, just copy !
248 *out++ = *in++;
249 continue;
250 } else if (*in >= 0x80) {
252 * We assume we have UTF-8 input.
254 if (outend - out < 11) break;
256 if (*in < 0xC0) {
257 xmlSaveErr(XML_SAVE_NOT_UTF8, NULL, NULL);
258 in++;
259 goto error;
260 } else if (*in < 0xE0) {
261 if (inend - in < 2) break;
262 val = (in[0]) & 0x1F;
263 val <<= 6;
264 val |= (in[1]) & 0x3F;
265 in += 2;
266 } else if (*in < 0xF0) {
267 if (inend - in < 3) break;
268 val = (in[0]) & 0x0F;
269 val <<= 6;
270 val |= (in[1]) & 0x3F;
271 val <<= 6;
272 val |= (in[2]) & 0x3F;
273 in += 3;
274 } else if (*in < 0xF8) {
275 if (inend - in < 4) break;
276 val = (in[0]) & 0x07;
277 val <<= 6;
278 val |= (in[1]) & 0x3F;
279 val <<= 6;
280 val |= (in[2]) & 0x3F;
281 val <<= 6;
282 val |= (in[3]) & 0x3F;
283 in += 4;
284 } else {
285 xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
286 in++;
287 goto error;
289 if (!IS_CHAR(val)) {
290 xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
291 in++;
292 goto error;
296 * We could do multiple things here. Just save as a char ref
298 out = xmlSerializeHexCharRef(out, val);
299 } else if (IS_BYTE_CHAR(*in)) {
300 if (outend - out < 6) break;
301 out = xmlSerializeHexCharRef(out, *in++);
302 } else {
303 xmlGenericError(xmlGenericErrorContext,
304 "xmlEscapeEntities : char out of range\n");
305 in++;
306 goto error;
309 *outlen = out - outstart;
310 *inlen = in - base;
311 return(0);
312 error:
313 *outlen = out - outstart;
314 *inlen = in - base;
315 return(-1);
318 /************************************************************************
320 * Allocation and deallocation *
322 ************************************************************************/
324 * xmlSaveCtxtInit:
325 * @ctxt: the saving context
327 * Initialize a saving context
329 static void
330 xmlSaveCtxtInit(xmlSaveCtxtPtr ctxt)
332 int i;
333 int len;
335 if (ctxt == NULL) return;
336 if ((ctxt->encoding == NULL) && (ctxt->escape == NULL))
337 ctxt->escape = xmlEscapeEntities;
338 len = xmlStrlen((xmlChar *)xmlTreeIndentString);
339 if ((xmlTreeIndentString == NULL) || (len == 0)) {
340 memset(&ctxt->indent[0], 0, MAX_INDENT + 1);
341 } else {
342 ctxt->indent_size = len;
343 ctxt->indent_nr = MAX_INDENT / ctxt->indent_size;
344 for (i = 0;i < ctxt->indent_nr;i++)
345 memcpy(&ctxt->indent[i * ctxt->indent_size], xmlTreeIndentString,
346 ctxt->indent_size);
347 ctxt->indent[ctxt->indent_nr * ctxt->indent_size] = 0;
350 if (xmlSaveNoEmptyTags) {
351 ctxt->options |= XML_SAVE_NO_EMPTY;
356 * xmlFreeSaveCtxt:
358 * Free a saving context, destroying the output in any remaining buffer
360 static void
361 xmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt)
363 if (ctxt == NULL) return;
364 if (ctxt->encoding != NULL)
365 xmlFree((char *) ctxt->encoding);
366 if (ctxt->buf != NULL)
367 xmlOutputBufferClose(ctxt->buf);
368 xmlFree(ctxt);
372 * xmlNewSaveCtxt:
374 * Create a new saving context
376 * Returns the new structure or NULL in case of error
378 static xmlSaveCtxtPtr
379 xmlNewSaveCtxt(const char *encoding, int options)
381 xmlSaveCtxtPtr ret;
383 ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt));
384 if (ret == NULL) {
385 xmlSaveErrMemory("creating saving context");
386 return ( NULL );
388 memset(ret, 0, sizeof(xmlSaveCtxt));
390 if (encoding != NULL) {
391 ret->handler = xmlFindCharEncodingHandler(encoding);
392 if (ret->handler == NULL) {
393 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
394 xmlFreeSaveCtxt(ret);
395 return(NULL);
397 ret->encoding = xmlStrdup((const xmlChar *)encoding);
398 ret->escape = NULL;
400 xmlSaveCtxtInit(ret);
403 * Use the options
406 /* Re-check this option as it may already have been set */
407 if ((ret->options & XML_SAVE_NO_EMPTY) && ! (options & XML_SAVE_NO_EMPTY)) {
408 options |= XML_SAVE_NO_EMPTY;
411 ret->options = options;
412 if (options & XML_SAVE_FORMAT)
413 ret->format = 1;
414 else if (options & XML_SAVE_WSNONSIG)
415 ret->format = 2;
417 return(ret);
420 /************************************************************************
422 * Dumping XML tree content to a simple buffer *
424 ************************************************************************/
426 * xmlAttrSerializeContent:
427 * @buf: the XML buffer output
428 * @doc: the document
429 * @attr: the attribute pointer
431 * Serialize the attribute in the buffer
433 static void
434 xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr)
436 xmlNodePtr children;
438 children = attr->children;
439 while (children != NULL) {
440 switch (children->type) {
441 case XML_TEXT_NODE:
442 xmlBufAttrSerializeTxtContent(buf->buffer, attr->doc,
443 attr, children->content);
444 break;
445 case XML_ENTITY_REF_NODE:
446 xmlBufAdd(buf->buffer, BAD_CAST "&", 1);
447 xmlBufAdd(buf->buffer, children->name,
448 xmlStrlen(children->name));
449 xmlBufAdd(buf->buffer, BAD_CAST ";", 1);
450 break;
451 default:
452 /* should not happen unless we have a badly built tree */
453 break;
455 children = children->next;
460 * xmlBufDumpNotationTable:
461 * @buf: an xmlBufPtr output
462 * @table: A notation table
464 * This will dump the content of the notation table as an XML DTD definition
466 void
467 xmlBufDumpNotationTable(xmlBufPtr buf, xmlNotationTablePtr table) {
468 xmlBufferPtr buffer;
470 buffer = xmlBufferCreate();
471 if (buffer == NULL) {
473 * TODO set the error in buf
475 return;
477 xmlDumpNotationTable(buffer, table);
478 xmlBufMergeBuffer(buf, buffer);
482 * xmlBufDumpElementDecl:
483 * @buf: an xmlBufPtr output
484 * @elem: An element table
486 * This will dump the content of the element declaration as an XML
487 * DTD definition
489 void
490 xmlBufDumpElementDecl(xmlBufPtr buf, xmlElementPtr elem) {
491 xmlBufferPtr buffer;
493 buffer = xmlBufferCreate();
494 if (buffer == NULL) {
496 * TODO set the error in buf
498 return;
500 xmlDumpElementDecl(buffer, elem);
501 xmlBufMergeBuffer(buf, buffer);
505 * xmlBufDumpAttributeDecl:
506 * @buf: an xmlBufPtr output
507 * @attr: An attribute declaration
509 * This will dump the content of the attribute declaration as an XML
510 * DTD definition
512 void
513 xmlBufDumpAttributeDecl(xmlBufPtr buf, xmlAttributePtr attr) {
514 xmlBufferPtr buffer;
516 buffer = xmlBufferCreate();
517 if (buffer == NULL) {
519 * TODO set the error in buf
521 return;
523 xmlDumpAttributeDecl(buffer, attr);
524 xmlBufMergeBuffer(buf, buffer);
528 * xmlBufDumpEntityDecl:
529 * @buf: an xmlBufPtr output
530 * @ent: An entity table
532 * This will dump the content of the entity table as an XML DTD definition
534 void
535 xmlBufDumpEntityDecl(xmlBufPtr buf, xmlEntityPtr ent) {
536 xmlBufferPtr buffer;
538 buffer = xmlBufferCreate();
539 if (buffer == NULL) {
541 * TODO set the error in buf
543 return;
545 xmlDumpEntityDecl(buffer, ent);
546 xmlBufMergeBuffer(buf, buffer);
549 /************************************************************************
551 * Dumping XML tree content to an I/O output buffer *
553 ************************************************************************/
555 static int xmlSaveSwitchEncoding(xmlSaveCtxtPtr ctxt, const char *encoding) {
556 xmlOutputBufferPtr buf = ctxt->buf;
558 if ((encoding != NULL) && (buf->encoder == NULL) && (buf->conv == NULL)) {
559 buf->encoder = xmlFindCharEncodingHandler((const char *)encoding);
560 if (buf->encoder == NULL) {
561 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL,
562 (const char *)encoding);
563 return(-1);
565 buf->conv = xmlBufCreate();
566 if (buf->conv == NULL) {
567 xmlCharEncCloseFunc(buf->encoder);
568 xmlSaveErrMemory("creating encoding buffer");
569 return(-1);
572 * initialize the state, e.g. if outputting a BOM
574 xmlCharEncOutput(buf, 1);
576 return(0);
579 static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) {
580 xmlOutputBufferPtr buf = ctxt->buf;
581 xmlOutputBufferFlush(buf);
582 xmlCharEncCloseFunc(buf->encoder);
583 xmlBufFree(buf->conv);
584 buf->encoder = NULL;
585 buf->conv = NULL;
586 return(0);
589 #ifdef LIBXML_HTML_ENABLED
590 static void
591 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
592 #endif
593 static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
594 void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
595 static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur);
598 * xmlOutputBufferWriteWSNonSig:
599 * @ctxt: The save context
600 * @extra: Number of extra indents to apply to ctxt->level
602 * Write out formatting for non-significant whitespace output.
604 static void
605 xmlOutputBufferWriteWSNonSig(xmlSaveCtxtPtr ctxt, int extra)
607 int i;
608 if ((ctxt == NULL) || (ctxt->buf == NULL))
609 return;
610 xmlOutputBufferWrite(ctxt->buf, 1, "\n");
611 for (i = 0; i < (ctxt->level + extra); i += ctxt->indent_nr) {
612 xmlOutputBufferWrite(ctxt->buf, ctxt->indent_size *
613 ((ctxt->level + extra - i) > ctxt->indent_nr ?
614 ctxt->indent_nr : (ctxt->level + extra - i)),
615 ctxt->indent);
620 * xmlNsDumpOutput:
621 * @buf: the XML buffer output
622 * @cur: a namespace
623 * @ctxt: the output save context. Optional.
625 * Dump a local Namespace definition.
626 * Should be called in the context of attributes dumps.
627 * If @ctxt is supplied, @buf should be its buffer.
629 static void
630 xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur, xmlSaveCtxtPtr ctxt) {
631 if ((cur == NULL) || (buf == NULL)) return;
632 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
633 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
634 return;
636 if (ctxt != NULL && ctxt->format == 2)
637 xmlOutputBufferWriteWSNonSig(ctxt, 2);
638 else
639 xmlOutputBufferWrite(buf, 1, " ");
641 /* Within the context of an element attributes */
642 if (cur->prefix != NULL) {
643 xmlOutputBufferWrite(buf, 6, "xmlns:");
644 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
645 } else
646 xmlOutputBufferWrite(buf, 5, "xmlns");
647 xmlOutputBufferWrite(buf, 1, "=");
648 xmlBufWriteQuotedString(buf->buffer, cur->href);
653 * xmlNsDumpOutputCtxt
654 * @ctxt: the save context
655 * @cur: a namespace
657 * Dump a local Namespace definition to a save context.
658 * Should be called in the context of attribute dumps.
660 static void
661 xmlNsDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) {
662 xmlNsDumpOutput(ctxt->buf, cur, ctxt);
666 * xmlNsListDumpOutputCtxt
667 * @ctxt: the save context
668 * @cur: the first namespace
670 * Dump a list of local namespace definitions to a save context.
671 * Should be called in the context of attribute dumps.
673 static void
674 xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) {
675 while (cur != NULL) {
676 xmlNsDumpOutput(ctxt->buf, cur, ctxt);
677 cur = cur->next;
682 * xmlNsListDumpOutput:
683 * @buf: the XML buffer output
684 * @cur: the first namespace
686 * Dump a list of local Namespace definitions.
687 * Should be called in the context of attributes dumps.
689 void
690 xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
691 while (cur != NULL) {
692 xmlNsDumpOutput(buf, cur, NULL);
693 cur = cur->next;
698 * xmlDtdDumpOutput:
699 * @buf: the XML buffer output
700 * @dtd: the pointer to the DTD
702 * Dump the XML document DTD, if any.
704 static void
705 xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
706 xmlOutputBufferPtr buf;
707 xmlNodePtr cur;
708 int format, level;
710 if (dtd == NULL) return;
711 if ((ctxt == NULL) || (ctxt->buf == NULL))
712 return;
713 buf = ctxt->buf;
714 xmlOutputBufferWrite(buf, 10, "<!DOCTYPE ");
715 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
716 if (dtd->ExternalID != NULL) {
717 xmlOutputBufferWrite(buf, 8, " PUBLIC ");
718 xmlBufWriteQuotedString(buf->buffer, dtd->ExternalID);
719 xmlOutputBufferWrite(buf, 1, " ");
720 xmlBufWriteQuotedString(buf->buffer, dtd->SystemID);
721 } else if (dtd->SystemID != NULL) {
722 xmlOutputBufferWrite(buf, 8, " SYSTEM ");
723 xmlBufWriteQuotedString(buf->buffer, dtd->SystemID);
725 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
726 (dtd->attributes == NULL) && (dtd->notations == NULL) &&
727 (dtd->pentities == NULL)) {
728 xmlOutputBufferWrite(buf, 1, ">");
729 return;
731 xmlOutputBufferWrite(buf, 3, " [\n");
733 * Dump the notations first they are not in the DTD children list
734 * Do this only on a standalone DTD or on the internal subset though.
736 if ((dtd->notations != NULL) && ((dtd->doc == NULL) ||
737 (dtd->doc->intSubset == dtd))) {
738 xmlBufDumpNotationTable(buf->buffer,
739 (xmlNotationTablePtr) dtd->notations);
741 format = ctxt->format;
742 level = ctxt->level;
743 ctxt->format = 0;
744 ctxt->level = -1;
745 for (cur = dtd->children; cur != NULL; cur = cur->next) {
746 xmlNodeDumpOutputInternal(ctxt, cur);
748 ctxt->format = format;
749 ctxt->level = level;
750 xmlOutputBufferWrite(buf, 2, "]>");
754 * xmlAttrDumpOutput:
755 * @buf: the XML buffer output
756 * @cur: the attribute pointer
758 * Dump an XML attribute
760 static void
761 xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
762 xmlOutputBufferPtr buf;
764 if (cur == NULL) return;
765 buf = ctxt->buf;
766 if (buf == NULL) return;
767 if (ctxt->format == 2)
768 xmlOutputBufferWriteWSNonSig(ctxt, 2);
769 else
770 xmlOutputBufferWrite(buf, 1, " ");
771 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
772 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
773 xmlOutputBufferWrite(buf, 1, ":");
775 xmlOutputBufferWriteString(buf, (const char *)cur->name);
776 xmlOutputBufferWrite(buf, 2, "=\"");
777 xmlAttrSerializeContent(buf, cur);
778 xmlOutputBufferWrite(buf, 1, "\"");
781 #ifdef LIBXML_HTML_ENABLED
783 * htmlNodeDumpOutputInternal:
784 * @cur: the current node
786 * Dump an HTML node, recursive behaviour, children are printed too.
788 static int
789 htmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
790 const xmlChar *oldenc = NULL;
791 const xmlChar *oldctxtenc = ctxt->encoding;
792 const xmlChar *encoding = ctxt->encoding;
793 xmlOutputBufferPtr buf = ctxt->buf;
794 int switched_encoding = 0;
795 xmlDocPtr doc;
797 xmlInitParser();
799 doc = cur->doc;
800 if (doc != NULL) {
801 oldenc = doc->encoding;
802 if (ctxt->encoding != NULL) {
803 doc->encoding = BAD_CAST ctxt->encoding;
804 } else if (doc->encoding != NULL) {
805 encoding = doc->encoding;
809 if ((encoding != NULL) && (doc != NULL))
810 htmlSetMetaEncoding(doc, (const xmlChar *) encoding);
811 if ((encoding == NULL) && (doc != NULL))
812 encoding = htmlGetMetaEncoding(doc);
813 if (encoding == NULL)
814 encoding = BAD_CAST "HTML";
815 if ((encoding != NULL) && (oldctxtenc == NULL) &&
816 (buf->encoder == NULL) && (buf->conv == NULL)) {
817 if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
818 doc->encoding = oldenc;
819 return(-1);
821 switched_encoding = 1;
823 if (ctxt->options & XML_SAVE_FORMAT)
824 htmlNodeDumpFormatOutput(buf, doc, cur,
825 (const char *)encoding, 1);
826 else
827 htmlNodeDumpFormatOutput(buf, doc, cur,
828 (const char *)encoding, 0);
830 * Restore the state of the saving context at the end of the document
832 if ((switched_encoding) && (oldctxtenc == NULL)) {
833 xmlSaveClearEncoding(ctxt);
835 if (doc != NULL)
836 doc->encoding = oldenc;
837 return(0);
839 #endif
842 * xmlNodeDumpOutputInternal:
843 * @cur: the current node
845 * Dump an XML node, recursive behaviour, children are printed too.
847 static void
848 xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
849 int format = ctxt->format;
850 xmlNodePtr tmp, root, unformattedNode = NULL;
851 xmlAttrPtr attr;
852 xmlChar *start, *end;
853 xmlOutputBufferPtr buf;
855 if (cur == NULL) return;
856 buf = ctxt->buf;
858 root = cur;
859 while (1) {
860 switch (cur->type) {
861 case XML_DOCUMENT_NODE:
862 case XML_HTML_DOCUMENT_NODE:
863 xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
864 break;
866 case XML_DTD_NODE:
867 xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
868 break;
870 case XML_DOCUMENT_FRAG_NODE:
871 if (cur->children != NULL) {
872 cur = cur->children;
873 continue;
875 break;
877 case XML_ELEMENT_DECL:
878 xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
879 break;
881 case XML_ATTRIBUTE_DECL:
882 xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
883 break;
885 case XML_ENTITY_DECL:
886 xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
887 break;
889 case XML_ELEMENT_NODE:
890 if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
891 xmlOutputBufferWrite(buf, ctxt->indent_size *
892 (ctxt->level > ctxt->indent_nr ?
893 ctxt->indent_nr : ctxt->level),
894 ctxt->indent);
896 xmlOutputBufferWrite(buf, 1, "<");
897 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
898 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
899 xmlOutputBufferWrite(buf, 1, ":");
901 xmlOutputBufferWriteString(buf, (const char *)cur->name);
902 if (cur->nsDef)
903 xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
904 for (attr = cur->properties; attr != NULL; attr = attr->next)
905 xmlAttrDumpOutput(ctxt, attr);
907 if (cur->children == NULL) {
908 if ((ctxt->options & XML_SAVE_NO_EMPTY) == 0) {
909 if (ctxt->format == 2)
910 xmlOutputBufferWriteWSNonSig(ctxt, 0);
911 xmlOutputBufferWrite(buf, 2, "/>");
912 } else {
913 if (ctxt->format == 2)
914 xmlOutputBufferWriteWSNonSig(ctxt, 1);
915 xmlOutputBufferWrite(buf, 3, "></");
916 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
917 xmlOutputBufferWriteString(buf,
918 (const char *)cur->ns->prefix);
919 xmlOutputBufferWrite(buf, 1, ":");
921 xmlOutputBufferWriteString(buf, (const char *)cur->name);
922 if (ctxt->format == 2)
923 xmlOutputBufferWriteWSNonSig(ctxt, 0);
924 xmlOutputBufferWrite(buf, 1, ">");
926 } else {
927 if (ctxt->format == 1) {
928 tmp = cur->children;
929 while (tmp != NULL) {
930 if ((tmp->type == XML_TEXT_NODE) ||
931 (tmp->type == XML_CDATA_SECTION_NODE) ||
932 (tmp->type == XML_ENTITY_REF_NODE)) {
933 ctxt->format = 0;
934 unformattedNode = cur;
935 break;
937 tmp = tmp->next;
940 if (ctxt->format == 2)
941 xmlOutputBufferWriteWSNonSig(ctxt, 1);
942 xmlOutputBufferWrite(buf, 1, ">");
943 if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
944 if (ctxt->level >= 0) ctxt->level++;
945 cur = cur->children;
946 continue;
949 break;
951 case XML_TEXT_NODE:
952 if (cur->content == NULL)
953 break;
954 if (cur->name != xmlStringTextNoenc) {
955 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
956 } else {
958 * Disable escaping, needed for XSLT
960 xmlOutputBufferWriteString(buf, (const char *) cur->content);
962 break;
964 case XML_PI_NODE:
965 if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
966 xmlOutputBufferWrite(buf, ctxt->indent_size *
967 (ctxt->level > ctxt->indent_nr ?
968 ctxt->indent_nr : ctxt->level),
969 ctxt->indent);
971 if (cur->content != NULL) {
972 xmlOutputBufferWrite(buf, 2, "<?");
973 xmlOutputBufferWriteString(buf, (const char *)cur->name);
974 if (cur->content != NULL) {
975 if (ctxt->format == 2)
976 xmlOutputBufferWriteWSNonSig(ctxt, 0);
977 else
978 xmlOutputBufferWrite(buf, 1, " ");
979 xmlOutputBufferWriteString(buf,
980 (const char *)cur->content);
982 xmlOutputBufferWrite(buf, 2, "?>");
983 } else {
984 xmlOutputBufferWrite(buf, 2, "<?");
985 xmlOutputBufferWriteString(buf, (const char *)cur->name);
986 if (ctxt->format == 2)
987 xmlOutputBufferWriteWSNonSig(ctxt, 0);
988 xmlOutputBufferWrite(buf, 2, "?>");
990 break;
992 case XML_COMMENT_NODE:
993 if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
994 xmlOutputBufferWrite(buf, ctxt->indent_size *
995 (ctxt->level > ctxt->indent_nr ?
996 ctxt->indent_nr : ctxt->level),
997 ctxt->indent);
999 if (cur->content != NULL) {
1000 xmlOutputBufferWrite(buf, 4, "<!--");
1001 xmlOutputBufferWriteString(buf, (const char *)cur->content);
1002 xmlOutputBufferWrite(buf, 3, "-->");
1004 break;
1006 case XML_ENTITY_REF_NODE:
1007 xmlOutputBufferWrite(buf, 1, "&");
1008 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1009 xmlOutputBufferWrite(buf, 1, ";");
1010 break;
1012 case XML_CDATA_SECTION_NODE:
1013 if (cur->content == NULL || *cur->content == '\0') {
1014 xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
1015 } else {
1016 start = end = cur->content;
1017 while (*end != '\0') {
1018 if ((*end == ']') && (*(end + 1) == ']') &&
1019 (*(end + 2) == '>')) {
1020 end = end + 2;
1021 xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1022 xmlOutputBufferWrite(buf, end - start,
1023 (const char *)start);
1024 xmlOutputBufferWrite(buf, 3, "]]>");
1025 start = end;
1027 end++;
1029 if (start != end) {
1030 xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1031 xmlOutputBufferWriteString(buf, (const char *)start);
1032 xmlOutputBufferWrite(buf, 3, "]]>");
1035 break;
1037 case XML_ATTRIBUTE_NODE:
1038 xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
1039 break;
1041 case XML_NAMESPACE_DECL:
1042 xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
1043 break;
1045 default:
1046 break;
1049 while (1) {
1050 if (cur == root)
1051 return;
1052 if ((ctxt->format == 1) &&
1053 (cur->type != XML_XINCLUDE_START) &&
1054 (cur->type != XML_XINCLUDE_END))
1055 xmlOutputBufferWrite(buf, 1, "\n");
1056 if (cur->next != NULL) {
1057 cur = cur->next;
1058 break;
1062 * The parent should never be NULL here but we want to handle
1063 * corrupted documents gracefully.
1065 if (cur->parent == NULL)
1066 return;
1067 cur = cur->parent;
1069 if (cur->type == XML_ELEMENT_NODE) {
1070 if (ctxt->level > 0) ctxt->level--;
1071 if ((xmlIndentTreeOutput) && (ctxt->format == 1))
1072 xmlOutputBufferWrite(buf, ctxt->indent_size *
1073 (ctxt->level > ctxt->indent_nr ?
1074 ctxt->indent_nr : ctxt->level),
1075 ctxt->indent);
1077 xmlOutputBufferWrite(buf, 2, "</");
1078 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1079 xmlOutputBufferWriteString(buf,
1080 (const char *)cur->ns->prefix);
1081 xmlOutputBufferWrite(buf, 1, ":");
1084 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1085 if (ctxt->format == 2)
1086 xmlOutputBufferWriteWSNonSig(ctxt, 0);
1087 xmlOutputBufferWrite(buf, 1, ">");
1089 if (cur == unformattedNode) {
1090 ctxt->format = format;
1091 unformattedNode = NULL;
1099 * xmlDocContentDumpOutput:
1100 * @cur: the document
1102 * Dump an XML document.
1104 static int
1105 xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) {
1106 #ifdef LIBXML_HTML_ENABLED
1107 xmlDtdPtr dtd;
1108 int is_xhtml = 0;
1109 #endif
1110 const xmlChar *oldenc = cur->encoding;
1111 const xmlChar *oldctxtenc = ctxt->encoding;
1112 const xmlChar *encoding = ctxt->encoding;
1113 xmlCharEncodingOutputFunc oldescape = ctxt->escape;
1114 xmlCharEncodingOutputFunc oldescapeAttr = ctxt->escapeAttr;
1115 xmlOutputBufferPtr buf = ctxt->buf;
1116 xmlCharEncoding enc;
1117 int switched_encoding = 0;
1119 xmlInitParser();
1121 if ((cur->type != XML_HTML_DOCUMENT_NODE) &&
1122 (cur->type != XML_DOCUMENT_NODE))
1123 return(-1);
1125 if (ctxt->encoding != NULL) {
1126 cur->encoding = BAD_CAST ctxt->encoding;
1127 } else if (cur->encoding != NULL) {
1128 encoding = cur->encoding;
1131 if (((cur->type == XML_HTML_DOCUMENT_NODE) &&
1132 ((ctxt->options & XML_SAVE_AS_XML) == 0) &&
1133 ((ctxt->options & XML_SAVE_XHTML) == 0)) ||
1134 (ctxt->options & XML_SAVE_AS_HTML)) {
1135 #ifdef LIBXML_HTML_ENABLED
1136 if (encoding != NULL)
1137 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
1138 if (encoding == NULL)
1139 encoding = htmlGetMetaEncoding(cur);
1140 if (encoding == NULL)
1141 encoding = BAD_CAST "HTML";
1142 if ((encoding != NULL) && (oldctxtenc == NULL) &&
1143 (buf->encoder == NULL) && (buf->conv == NULL)) {
1144 if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
1145 cur->encoding = oldenc;
1146 return(-1);
1149 if (ctxt->options & XML_SAVE_FORMAT)
1150 htmlDocContentDumpFormatOutput(buf, cur,
1151 (const char *)encoding, 1);
1152 else
1153 htmlDocContentDumpFormatOutput(buf, cur,
1154 (const char *)encoding, 0);
1155 if (ctxt->encoding != NULL)
1156 cur->encoding = oldenc;
1157 return(0);
1158 #else
1159 return(-1);
1160 #endif
1161 } else if ((cur->type == XML_DOCUMENT_NODE) ||
1162 (ctxt->options & XML_SAVE_AS_XML) ||
1163 (ctxt->options & XML_SAVE_XHTML)) {
1164 enc = xmlParseCharEncoding((const char*) encoding);
1165 if ((encoding != NULL) && (oldctxtenc == NULL) &&
1166 (buf->encoder == NULL) && (buf->conv == NULL) &&
1167 ((ctxt->options & XML_SAVE_NO_DECL) == 0)) {
1168 if ((enc != XML_CHAR_ENCODING_UTF8) &&
1169 (enc != XML_CHAR_ENCODING_NONE) &&
1170 (enc != XML_CHAR_ENCODING_ASCII)) {
1172 * we need to switch to this encoding but just for this
1173 * document since we output the XMLDecl the conversion
1174 * must be done to not generate not well formed documents.
1176 if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
1177 cur->encoding = oldenc;
1178 return(-1);
1180 switched_encoding = 1;
1182 if (ctxt->escape == xmlEscapeEntities)
1183 ctxt->escape = NULL;
1184 if (ctxt->escapeAttr == xmlEscapeEntities)
1185 ctxt->escapeAttr = NULL;
1190 * Save the XML declaration
1192 if ((ctxt->options & XML_SAVE_NO_DECL) == 0) {
1193 xmlOutputBufferWrite(buf, 14, "<?xml version=");
1194 if (cur->version != NULL)
1195 xmlBufWriteQuotedString(buf->buffer, cur->version);
1196 else
1197 xmlOutputBufferWrite(buf, 5, "\"1.0\"");
1198 if (encoding != NULL) {
1199 xmlOutputBufferWrite(buf, 10, " encoding=");
1200 xmlBufWriteQuotedString(buf->buffer, (xmlChar *) encoding);
1202 switch (cur->standalone) {
1203 case 0:
1204 xmlOutputBufferWrite(buf, 16, " standalone=\"no\"");
1205 break;
1206 case 1:
1207 xmlOutputBufferWrite(buf, 17, " standalone=\"yes\"");
1208 break;
1210 xmlOutputBufferWrite(buf, 3, "?>\n");
1213 #ifdef LIBXML_HTML_ENABLED
1214 if (ctxt->options & XML_SAVE_XHTML)
1215 is_xhtml = 1;
1216 if ((ctxt->options & XML_SAVE_NO_XHTML) == 0) {
1217 dtd = xmlGetIntSubset(cur);
1218 if (dtd != NULL) {
1219 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
1220 if (is_xhtml < 0) is_xhtml = 0;
1223 #endif
1224 if (cur->children != NULL) {
1225 xmlNodePtr child = cur->children;
1227 while (child != NULL) {
1228 ctxt->level = 0;
1229 #ifdef LIBXML_HTML_ENABLED
1230 if (is_xhtml)
1231 xhtmlNodeDumpOutput(ctxt, child);
1232 else
1233 #endif
1234 xmlNodeDumpOutputInternal(ctxt, child);
1235 if ((child->type != XML_XINCLUDE_START) &&
1236 (child->type != XML_XINCLUDE_END))
1237 xmlOutputBufferWrite(buf, 1, "\n");
1238 child = child->next;
1244 * Restore the state of the saving context at the end of the document
1246 if ((switched_encoding) && (oldctxtenc == NULL)) {
1247 xmlSaveClearEncoding(ctxt);
1248 ctxt->escape = oldescape;
1249 ctxt->escapeAttr = oldescapeAttr;
1251 cur->encoding = oldenc;
1252 return(0);
1255 #ifdef LIBXML_HTML_ENABLED
1256 /************************************************************************
1258 * Functions specific to XHTML serialization *
1260 ************************************************************************/
1263 * xhtmlIsEmpty:
1264 * @node: the node
1266 * Check if a node is an empty xhtml node
1268 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
1270 static int
1271 xhtmlIsEmpty(xmlNodePtr node) {
1272 if (node == NULL)
1273 return(-1);
1274 if (node->type != XML_ELEMENT_NODE)
1275 return(0);
1276 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
1277 return(0);
1278 if (node->children != NULL)
1279 return(0);
1280 switch (node->name[0]) {
1281 case 'a':
1282 if (xmlStrEqual(node->name, BAD_CAST "area"))
1283 return(1);
1284 return(0);
1285 case 'b':
1286 if (xmlStrEqual(node->name, BAD_CAST "br"))
1287 return(1);
1288 if (xmlStrEqual(node->name, BAD_CAST "base"))
1289 return(1);
1290 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
1291 return(1);
1292 return(0);
1293 case 'c':
1294 if (xmlStrEqual(node->name, BAD_CAST "col"))
1295 return(1);
1296 return(0);
1297 case 'f':
1298 if (xmlStrEqual(node->name, BAD_CAST "frame"))
1299 return(1);
1300 return(0);
1301 case 'h':
1302 if (xmlStrEqual(node->name, BAD_CAST "hr"))
1303 return(1);
1304 return(0);
1305 case 'i':
1306 if (xmlStrEqual(node->name, BAD_CAST "img"))
1307 return(1);
1308 if (xmlStrEqual(node->name, BAD_CAST "input"))
1309 return(1);
1310 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
1311 return(1);
1312 return(0);
1313 case 'l':
1314 if (xmlStrEqual(node->name, BAD_CAST "link"))
1315 return(1);
1316 return(0);
1317 case 'm':
1318 if (xmlStrEqual(node->name, BAD_CAST "meta"))
1319 return(1);
1320 return(0);
1321 case 'p':
1322 if (xmlStrEqual(node->name, BAD_CAST "param"))
1323 return(1);
1324 return(0);
1326 return(0);
1330 * xhtmlAttrListDumpOutput:
1331 * @cur: the first attribute pointer
1333 * Dump a list of XML attributes
1335 static void
1336 xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
1337 xmlAttrPtr xml_lang = NULL;
1338 xmlAttrPtr lang = NULL;
1339 xmlAttrPtr name = NULL;
1340 xmlAttrPtr id = NULL;
1341 xmlNodePtr parent;
1342 xmlOutputBufferPtr buf;
1344 if (cur == NULL) return;
1345 buf = ctxt->buf;
1346 parent = cur->parent;
1347 while (cur != NULL) {
1348 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
1349 id = cur;
1350 else
1351 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
1352 name = cur;
1353 else
1354 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
1355 lang = cur;
1356 else
1357 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
1358 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
1359 xml_lang = cur;
1360 else if ((cur->ns == NULL) &&
1361 ((cur->children == NULL) ||
1362 (cur->children->content == NULL) ||
1363 (cur->children->content[0] == 0)) &&
1364 (htmlIsBooleanAttr(cur->name))) {
1365 if (cur->children != NULL)
1366 xmlFreeNode(cur->children);
1367 cur->children = xmlNewText(cur->name);
1368 if (cur->children != NULL)
1369 cur->children->parent = (xmlNodePtr) cur;
1371 xmlAttrDumpOutput(ctxt, cur);
1372 cur = cur->next;
1375 * C.8
1377 if ((name != NULL) && (id == NULL)) {
1378 if ((parent != NULL) && (parent->name != NULL) &&
1379 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
1380 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
1381 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
1382 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
1383 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
1384 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
1385 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
1386 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
1387 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
1388 xmlOutputBufferWrite(buf, 5, " id=\"");
1389 xmlAttrSerializeContent(buf, name);
1390 xmlOutputBufferWrite(buf, 1, "\"");
1394 * C.7.
1396 if ((lang != NULL) && (xml_lang == NULL)) {
1397 xmlOutputBufferWrite(buf, 11, " xml:lang=\"");
1398 xmlAttrSerializeContent(buf, lang);
1399 xmlOutputBufferWrite(buf, 1, "\"");
1400 } else
1401 if ((xml_lang != NULL) && (lang == NULL)) {
1402 xmlOutputBufferWrite(buf, 7, " lang=\"");
1403 xmlAttrSerializeContent(buf, xml_lang);
1404 xmlOutputBufferWrite(buf, 1, "\"");
1409 * xhtmlNodeDumpOutput:
1410 * @buf: the XML buffer output
1411 * @doc: the XHTML document
1412 * @cur: the current node
1413 * @level: the imbrication level for indenting
1414 * @format: is formatting allowed
1415 * @encoding: an optional encoding string
1417 * Dump an XHTML node, recursive behaviour, children are printed too.
1419 static void
1420 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
1421 int format = ctxt->format, addmeta;
1422 xmlNodePtr tmp, root, unformattedNode = NULL;
1423 xmlChar *start, *end;
1424 xmlOutputBufferPtr buf = ctxt->buf;
1426 if (cur == NULL) return;
1428 root = cur;
1429 while (1) {
1430 switch (cur->type) {
1431 case XML_DOCUMENT_NODE:
1432 case XML_HTML_DOCUMENT_NODE:
1433 xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
1434 break;
1436 case XML_NAMESPACE_DECL:
1437 xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
1438 break;
1440 case XML_DTD_NODE:
1441 xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
1442 break;
1444 case XML_DOCUMENT_FRAG_NODE:
1445 if (cur->children) {
1446 cur = cur->children;
1447 continue;
1449 break;
1451 case XML_ELEMENT_DECL:
1452 xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
1453 break;
1455 case XML_ATTRIBUTE_DECL:
1456 xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
1457 break;
1459 case XML_ENTITY_DECL:
1460 xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
1461 break;
1463 case XML_ELEMENT_NODE:
1464 addmeta = 0;
1466 if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
1467 xmlOutputBufferWrite(buf, ctxt->indent_size *
1468 (ctxt->level > ctxt->indent_nr ?
1469 ctxt->indent_nr : ctxt->level),
1470 ctxt->indent);
1472 xmlOutputBufferWrite(buf, 1, "<");
1473 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1474 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
1475 xmlOutputBufferWrite(buf, 1, ":");
1478 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1479 if (cur->nsDef)
1480 xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
1481 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
1482 (cur->ns == NULL) && (cur->nsDef == NULL))) {
1484 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
1486 xmlOutputBufferWriteString(buf,
1487 " xmlns=\"http://www.w3.org/1999/xhtml\"");
1489 if (cur->properties != NULL)
1490 xhtmlAttrListDumpOutput(ctxt, cur->properties);
1492 if ((cur->parent != NULL) &&
1493 (cur->parent->parent == (xmlNodePtr) cur->doc) &&
1494 xmlStrEqual(cur->name, BAD_CAST"head") &&
1495 xmlStrEqual(cur->parent->name, BAD_CAST"html")) {
1497 tmp = cur->children;
1498 while (tmp != NULL) {
1499 if (xmlStrEqual(tmp->name, BAD_CAST"meta")) {
1500 xmlChar *httpequiv;
1502 httpequiv = xmlGetProp(tmp, BAD_CAST"http-equiv");
1503 if (httpequiv != NULL) {
1504 if (xmlStrcasecmp(httpequiv,
1505 BAD_CAST"Content-Type") == 0) {
1506 xmlFree(httpequiv);
1507 break;
1509 xmlFree(httpequiv);
1512 tmp = tmp->next;
1514 if (tmp == NULL)
1515 addmeta = 1;
1518 if (cur->children == NULL) {
1519 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
1520 ((xhtmlIsEmpty(cur) == 1) && (addmeta == 0))) {
1522 * C.2. Empty Elements
1524 xmlOutputBufferWrite(buf, 3, " />");
1525 } else {
1526 if (addmeta == 1) {
1527 xmlOutputBufferWrite(buf, 1, ">");
1528 if (ctxt->format == 1) {
1529 xmlOutputBufferWrite(buf, 1, "\n");
1530 if (xmlIndentTreeOutput)
1531 xmlOutputBufferWrite(buf, ctxt->indent_size *
1532 (ctxt->level + 1 > ctxt->indent_nr ?
1533 ctxt->indent_nr : ctxt->level + 1),
1534 ctxt->indent);
1536 xmlOutputBufferWriteString(buf,
1537 "<meta http-equiv=\"Content-Type\" "
1538 "content=\"text/html; charset=");
1539 if (ctxt->encoding) {
1540 xmlOutputBufferWriteString(buf,
1541 (const char *)ctxt->encoding);
1542 } else {
1543 xmlOutputBufferWrite(buf, 5, "UTF-8");
1545 xmlOutputBufferWrite(buf, 4, "\" />");
1546 if (ctxt->format == 1)
1547 xmlOutputBufferWrite(buf, 1, "\n");
1548 } else {
1549 xmlOutputBufferWrite(buf, 1, ">");
1552 * C.3. Element Minimization and Empty Element Content
1554 xmlOutputBufferWrite(buf, 2, "</");
1555 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1556 xmlOutputBufferWriteString(buf,
1557 (const char *)cur->ns->prefix);
1558 xmlOutputBufferWrite(buf, 1, ":");
1560 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1561 xmlOutputBufferWrite(buf, 1, ">");
1563 } else {
1564 xmlOutputBufferWrite(buf, 1, ">");
1565 if (addmeta == 1) {
1566 if (ctxt->format == 1) {
1567 xmlOutputBufferWrite(buf, 1, "\n");
1568 if (xmlIndentTreeOutput)
1569 xmlOutputBufferWrite(buf, ctxt->indent_size *
1570 (ctxt->level + 1 > ctxt->indent_nr ?
1571 ctxt->indent_nr : ctxt->level + 1),
1572 ctxt->indent);
1574 xmlOutputBufferWriteString(buf,
1575 "<meta http-equiv=\"Content-Type\" "
1576 "content=\"text/html; charset=");
1577 if (ctxt->encoding) {
1578 xmlOutputBufferWriteString(buf,
1579 (const char *)ctxt->encoding);
1580 } else {
1581 xmlOutputBufferWrite(buf, 5, "UTF-8");
1583 xmlOutputBufferWrite(buf, 4, "\" />");
1586 if (ctxt->format == 1) {
1587 tmp = cur->children;
1588 while (tmp != NULL) {
1589 if ((tmp->type == XML_TEXT_NODE) ||
1590 (tmp->type == XML_ENTITY_REF_NODE)) {
1591 unformattedNode = cur;
1592 ctxt->format = 0;
1593 break;
1595 tmp = tmp->next;
1599 if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
1600 if (ctxt->level >= 0) ctxt->level++;
1601 cur = cur->children;
1602 continue;
1605 break;
1607 case XML_TEXT_NODE:
1608 if (cur->content == NULL)
1609 break;
1610 if ((cur->name == xmlStringText) ||
1611 (cur->name != xmlStringTextNoenc)) {
1612 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
1613 } else {
1615 * Disable escaping, needed for XSLT
1617 xmlOutputBufferWriteString(buf, (const char *) cur->content);
1619 break;
1621 case XML_PI_NODE:
1622 if (cur->content != NULL) {
1623 xmlOutputBufferWrite(buf, 2, "<?");
1624 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1625 if (cur->content != NULL) {
1626 xmlOutputBufferWrite(buf, 1, " ");
1627 xmlOutputBufferWriteString(buf,
1628 (const char *)cur->content);
1630 xmlOutputBufferWrite(buf, 2, "?>");
1631 } else {
1632 xmlOutputBufferWrite(buf, 2, "<?");
1633 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1634 xmlOutputBufferWrite(buf, 2, "?>");
1636 break;
1638 case XML_COMMENT_NODE:
1639 if (cur->content != NULL) {
1640 xmlOutputBufferWrite(buf, 4, "<!--");
1641 xmlOutputBufferWriteString(buf, (const char *)cur->content);
1642 xmlOutputBufferWrite(buf, 3, "-->");
1644 break;
1646 case XML_ENTITY_REF_NODE:
1647 xmlOutputBufferWrite(buf, 1, "&");
1648 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1649 xmlOutputBufferWrite(buf, 1, ";");
1650 break;
1652 case XML_CDATA_SECTION_NODE:
1653 if (cur->content == NULL || *cur->content == '\0') {
1654 xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
1655 } else {
1656 start = end = cur->content;
1657 while (*end != '\0') {
1658 if (*end == ']' && *(end + 1) == ']' &&
1659 *(end + 2) == '>') {
1660 end = end + 2;
1661 xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1662 xmlOutputBufferWrite(buf, end - start,
1663 (const char *)start);
1664 xmlOutputBufferWrite(buf, 3, "]]>");
1665 start = end;
1667 end++;
1669 if (start != end) {
1670 xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1671 xmlOutputBufferWriteString(buf, (const char *)start);
1672 xmlOutputBufferWrite(buf, 3, "]]>");
1675 break;
1677 case XML_ATTRIBUTE_NODE:
1678 xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
1679 break;
1681 default:
1682 break;
1685 while (1) {
1686 if (cur == root)
1687 return;
1688 if (ctxt->format == 1)
1689 xmlOutputBufferWrite(buf, 1, "\n");
1690 if (cur->next != NULL) {
1691 cur = cur->next;
1692 break;
1696 * The parent should never be NULL here but we want to handle
1697 * corrupted documents gracefully.
1699 if (cur->parent == NULL)
1700 return;
1701 cur = cur->parent;
1703 if (cur->type == XML_ELEMENT_NODE) {
1704 if (ctxt->level > 0) ctxt->level--;
1705 if ((xmlIndentTreeOutput) && (ctxt->format == 1))
1706 xmlOutputBufferWrite(buf, ctxt->indent_size *
1707 (ctxt->level > ctxt->indent_nr ?
1708 ctxt->indent_nr : ctxt->level),
1709 ctxt->indent);
1711 xmlOutputBufferWrite(buf, 2, "</");
1712 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1713 xmlOutputBufferWriteString(buf,
1714 (const char *)cur->ns->prefix);
1715 xmlOutputBufferWrite(buf, 1, ":");
1718 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1719 xmlOutputBufferWrite(buf, 1, ">");
1721 if (cur == unformattedNode) {
1722 ctxt->format = format;
1723 unformattedNode = NULL;
1729 #endif
1731 /************************************************************************
1733 * Public entry points *
1735 ************************************************************************/
1738 * xmlSaveToFd:
1739 * @fd: a file descriptor number
1740 * @encoding: the encoding name to use or NULL
1741 * @options: a set of xmlSaveOptions
1743 * Create a document saving context serializing to a file descriptor
1744 * with the encoding and the options given.
1746 * Returns a new serialization context or NULL in case of error.
1748 xmlSaveCtxtPtr
1749 xmlSaveToFd(int fd, const char *encoding, int options)
1751 xmlSaveCtxtPtr ret;
1753 ret = xmlNewSaveCtxt(encoding, options);
1754 if (ret == NULL) return(NULL);
1755 ret->buf = xmlOutputBufferCreateFd(fd, ret->handler);
1756 if (ret->buf == NULL) {
1757 xmlCharEncCloseFunc(ret->handler);
1758 xmlFreeSaveCtxt(ret);
1759 return(NULL);
1761 return(ret);
1765 * xmlSaveToFilename:
1766 * @filename: a file name or an URL
1767 * @encoding: the encoding name to use or NULL
1768 * @options: a set of xmlSaveOptions
1770 * Create a document saving context serializing to a filename or possibly
1771 * to an URL (but this is less reliable) with the encoding and the options
1772 * given.
1774 * Returns a new serialization context or NULL in case of error.
1776 xmlSaveCtxtPtr
1777 xmlSaveToFilename(const char *filename, const char *encoding, int options)
1779 xmlSaveCtxtPtr ret;
1780 int compression = 0; /* TODO handle compression option */
1782 ret = xmlNewSaveCtxt(encoding, options);
1783 if (ret == NULL) return(NULL);
1784 ret->buf = xmlOutputBufferCreateFilename(filename, ret->handler,
1785 compression);
1786 if (ret->buf == NULL) {
1787 xmlCharEncCloseFunc(ret->handler);
1788 xmlFreeSaveCtxt(ret);
1789 return(NULL);
1791 return(ret);
1795 * xmlSaveToBuffer:
1796 * @buffer: a buffer
1797 * @encoding: the encoding name to use or NULL
1798 * @options: a set of xmlSaveOptions
1800 * Create a document saving context serializing to a buffer
1801 * with the encoding and the options given
1803 * Returns a new serialization context or NULL in case of error.
1806 xmlSaveCtxtPtr
1807 xmlSaveToBuffer(xmlBufferPtr buffer, const char *encoding, int options)
1809 xmlSaveCtxtPtr ret;
1811 ret = xmlNewSaveCtxt(encoding, options);
1812 if (ret == NULL) return(NULL);
1813 ret->buf = xmlOutputBufferCreateBuffer(buffer, ret->handler);
1814 if (ret->buf == NULL) {
1815 xmlCharEncCloseFunc(ret->handler);
1816 xmlFreeSaveCtxt(ret);
1817 return(NULL);
1819 return(ret);
1823 * xmlSaveToIO:
1824 * @iowrite: an I/O write function
1825 * @ioclose: an I/O close function
1826 * @ioctx: an I/O handler
1827 * @encoding: the encoding name to use or NULL
1828 * @options: a set of xmlSaveOptions
1830 * Create a document saving context serializing to a file descriptor
1831 * with the encoding and the options given
1833 * Returns a new serialization context or NULL in case of error.
1835 xmlSaveCtxtPtr
1836 xmlSaveToIO(xmlOutputWriteCallback iowrite,
1837 xmlOutputCloseCallback ioclose,
1838 void *ioctx, const char *encoding, int options)
1840 xmlSaveCtxtPtr ret;
1842 ret = xmlNewSaveCtxt(encoding, options);
1843 if (ret == NULL) return(NULL);
1844 ret->buf = xmlOutputBufferCreateIO(iowrite, ioclose, ioctx, ret->handler);
1845 if (ret->buf == NULL) {
1846 xmlCharEncCloseFunc(ret->handler);
1847 xmlFreeSaveCtxt(ret);
1848 return(NULL);
1850 return(ret);
1854 * xmlSaveDoc:
1855 * @ctxt: a document saving context
1856 * @doc: a document
1858 * Save a full document to a saving context
1859 * TODO: The function is not fully implemented yet as it does not return the
1860 * byte count but 0 instead
1862 * Returns the number of byte written or -1 in case of error
1864 long
1865 xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc)
1867 long ret = 0;
1869 if ((ctxt == NULL) || (doc == NULL)) return(-1);
1870 if (xmlDocContentDumpOutput(ctxt, doc) < 0)
1871 return(-1);
1872 return(ret);
1876 * xmlSaveTree:
1877 * @ctxt: a document saving context
1878 * @node: the top node of the subtree to save
1880 * Save a subtree starting at the node parameter to a saving context
1881 * TODO: The function is not fully implemented yet as it does not return the
1882 * byte count but 0 instead
1884 * Returns the number of byte written or -1 in case of error
1886 long
1887 xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr cur)
1889 long ret = 0;
1891 if ((ctxt == NULL) || (cur == NULL)) return(-1);
1892 #ifdef LIBXML_HTML_ENABLED
1893 if (ctxt->options & XML_SAVE_XHTML) {
1894 xhtmlNodeDumpOutput(ctxt, cur);
1895 return(ret);
1897 if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
1898 (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
1899 ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
1900 (ctxt->options & XML_SAVE_AS_HTML)) {
1901 htmlNodeDumpOutputInternal(ctxt, cur);
1902 return(ret);
1904 #endif
1905 xmlNodeDumpOutputInternal(ctxt, cur);
1906 return(ret);
1910 * xmlSaveFlush:
1911 * @ctxt: a document saving context
1913 * Flush a document saving context, i.e. make sure that all bytes have
1914 * been output.
1916 * Returns the number of byte written or -1 in case of error.
1919 xmlSaveFlush(xmlSaveCtxtPtr ctxt)
1921 if (ctxt == NULL) return(-1);
1922 if (ctxt->buf == NULL) return(-1);
1923 return(xmlOutputBufferFlush(ctxt->buf));
1927 * xmlSaveClose:
1928 * @ctxt: a document saving context
1930 * Close a document saving context, i.e. make sure that all bytes have
1931 * been output and free the associated data.
1933 * Returns the number of byte written or -1 in case of error.
1936 xmlSaveClose(xmlSaveCtxtPtr ctxt)
1938 int ret;
1940 if (ctxt == NULL) return(-1);
1941 ret = xmlSaveFlush(ctxt);
1942 xmlFreeSaveCtxt(ctxt);
1943 return(ret);
1947 * xmlSaveSetEscape:
1948 * @ctxt: a document saving context
1949 * @escape: the escaping function
1951 * Set a custom escaping function to be used for text in element content
1953 * Returns 0 if successful or -1 in case of error.
1956 xmlSaveSetEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
1958 if (ctxt == NULL) return(-1);
1959 ctxt->escape = escape;
1960 return(0);
1964 * xmlSaveSetAttrEscape:
1965 * @ctxt: a document saving context
1966 * @escape: the escaping function
1968 * Set a custom escaping function to be used for text in attribute content
1970 * Returns 0 if successful or -1 in case of error.
1973 xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
1975 if (ctxt == NULL) return(-1);
1976 ctxt->escapeAttr = escape;
1977 return(0);
1980 /************************************************************************
1982 * Public entry points based on buffers *
1984 ************************************************************************/
1987 * xmlBufAttrSerializeTxtContent:
1988 * @buf: and xmlBufPtr output
1989 * @doc: the document
1990 * @attr: the attribute node
1991 * @string: the text content
1993 * Serialize text attribute values to an xmlBufPtr
1995 void
1996 xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc,
1997 xmlAttrPtr attr, const xmlChar * string)
1999 xmlChar *base, *cur;
2001 if (string == NULL)
2002 return;
2003 base = cur = (xmlChar *) string;
2004 while (*cur != 0) {
2005 if (*cur == '\n') {
2006 if (base != cur)
2007 xmlBufAdd(buf, base, cur - base);
2008 xmlBufAdd(buf, BAD_CAST "&#10;", 5);
2009 cur++;
2010 base = cur;
2011 } else if (*cur == '\r') {
2012 if (base != cur)
2013 xmlBufAdd(buf, base, cur - base);
2014 xmlBufAdd(buf, BAD_CAST "&#13;", 5);
2015 cur++;
2016 base = cur;
2017 } else if (*cur == '\t') {
2018 if (base != cur)
2019 xmlBufAdd(buf, base, cur - base);
2020 xmlBufAdd(buf, BAD_CAST "&#9;", 4);
2021 cur++;
2022 base = cur;
2023 } else if (*cur == '"') {
2024 if (base != cur)
2025 xmlBufAdd(buf, base, cur - base);
2026 xmlBufAdd(buf, BAD_CAST "&quot;", 6);
2027 cur++;
2028 base = cur;
2029 } else if (*cur == '<') {
2030 if (base != cur)
2031 xmlBufAdd(buf, base, cur - base);
2032 xmlBufAdd(buf, BAD_CAST "&lt;", 4);
2033 cur++;
2034 base = cur;
2035 } else if (*cur == '>') {
2036 if (base != cur)
2037 xmlBufAdd(buf, base, cur - base);
2038 xmlBufAdd(buf, BAD_CAST "&gt;", 4);
2039 cur++;
2040 base = cur;
2041 } else if (*cur == '&') {
2042 if (base != cur)
2043 xmlBufAdd(buf, base, cur - base);
2044 xmlBufAdd(buf, BAD_CAST "&amp;", 5);
2045 cur++;
2046 base = cur;
2047 } else if ((*cur >= 0x80) && (cur[1] != 0) &&
2048 ((doc == NULL) || (doc->encoding == NULL))) {
2050 * We assume we have UTF-8 content.
2052 unsigned char tmp[12];
2053 int val = 0, l = 1;
2055 if (base != cur)
2056 xmlBufAdd(buf, base, cur - base);
2057 if (*cur < 0xC0) {
2058 xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL);
2059 xmlSerializeHexCharRef(tmp, *cur);
2060 xmlBufAdd(buf, (xmlChar *) tmp, -1);
2061 cur++;
2062 base = cur;
2063 continue;
2064 } else if (*cur < 0xE0) {
2065 val = (cur[0]) & 0x1F;
2066 val <<= 6;
2067 val |= (cur[1]) & 0x3F;
2068 l = 2;
2069 } else if ((*cur < 0xF0) && (cur [2] != 0)) {
2070 val = (cur[0]) & 0x0F;
2071 val <<= 6;
2072 val |= (cur[1]) & 0x3F;
2073 val <<= 6;
2074 val |= (cur[2]) & 0x3F;
2075 l = 3;
2076 } else if ((*cur < 0xF8) && (cur [2] != 0) && (cur[3] != 0)) {
2077 val = (cur[0]) & 0x07;
2078 val <<= 6;
2079 val |= (cur[1]) & 0x3F;
2080 val <<= 6;
2081 val |= (cur[2]) & 0x3F;
2082 val <<= 6;
2083 val |= (cur[3]) & 0x3F;
2084 l = 4;
2086 if ((l == 1) || (!IS_CHAR(val))) {
2087 xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL);
2088 xmlSerializeHexCharRef(tmp, *cur);
2089 xmlBufAdd(buf, (xmlChar *) tmp, -1);
2090 cur++;
2091 base = cur;
2092 continue;
2095 * We could do multiple things here. Just save
2096 * as a char ref
2098 xmlSerializeHexCharRef(tmp, val);
2099 xmlBufAdd(buf, (xmlChar *) tmp, -1);
2100 cur += l;
2101 base = cur;
2102 } else {
2103 cur++;
2106 if (base != cur)
2107 xmlBufAdd(buf, base, cur - base);
2111 * xmlAttrSerializeTxtContent:
2112 * @buf: the XML buffer output
2113 * @doc: the document
2114 * @attr: the attribute node
2115 * @string: the text content
2117 * Serialize text attribute values to an xml simple buffer
2119 void
2120 xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc,
2121 xmlAttrPtr attr, const xmlChar * string)
2123 xmlBufPtr buffer;
2125 if ((buf == NULL) || (string == NULL))
2126 return;
2127 buffer = xmlBufFromBuffer(buf);
2128 if (buffer == NULL)
2129 return;
2130 xmlBufAttrSerializeTxtContent(buffer, doc, attr, string);
2131 xmlBufBackToBuffer(buffer);
2135 * xmlNodeDump:
2136 * @buf: the XML buffer output
2137 * @doc: the document
2138 * @cur: the current node
2139 * @level: the imbrication level for indenting
2140 * @format: is formatting allowed
2142 * Dump an XML node, recursive behaviour,children are printed too.
2143 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2144 * or xmlKeepBlanksDefault(0) was called.
2145 * Since this is using xmlBuffer structures it is limited to 2GB and somehow
2146 * deprecated, use xmlNodeDumpOutput() instead.
2148 * Returns the number of bytes written to the buffer or -1 in case of error
2151 xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
2152 int format)
2154 xmlBufPtr buffer;
2155 size_t ret;
2157 if ((buf == NULL) || (cur == NULL))
2158 return(-1);
2159 buffer = xmlBufFromBuffer(buf);
2160 if (buffer == NULL)
2161 return(-1);
2162 ret = xmlBufNodeDump(buffer, doc, cur, level, format);
2163 xmlBufBackToBuffer(buffer);
2164 if (ret > INT_MAX)
2165 return(-1);
2166 return((int) ret);
2170 * xmlBufNodeDump:
2171 * @buf: the XML buffer output
2172 * @doc: the document
2173 * @cur: the current node
2174 * @level: the imbrication level for indenting
2175 * @format: is formatting allowed
2177 * Dump an XML node, recursive behaviour,children are printed too.
2178 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2179 * or xmlKeepBlanksDefault(0) was called
2181 * Returns the number of bytes written to the buffer, in case of error 0
2182 * is returned or @buf stores the error
2185 size_t
2186 xmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
2187 int format)
2189 size_t use;
2190 int ret;
2191 xmlOutputBufferPtr outbuf;
2192 int oldalloc;
2194 xmlInitParser();
2196 if (cur == NULL) {
2197 #ifdef DEBUG_TREE
2198 xmlGenericError(xmlGenericErrorContext,
2199 "xmlNodeDump : node == NULL\n");
2200 #endif
2201 return (-1);
2203 if (buf == NULL) {
2204 #ifdef DEBUG_TREE
2205 xmlGenericError(xmlGenericErrorContext,
2206 "xmlNodeDump : buf == NULL\n");
2207 #endif
2208 return (-1);
2210 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2211 if (outbuf == NULL) {
2212 xmlSaveErrMemory("creating buffer");
2213 return (-1);
2215 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
2216 outbuf->buffer = buf;
2217 outbuf->encoder = NULL;
2218 outbuf->writecallback = NULL;
2219 outbuf->closecallback = NULL;
2220 outbuf->context = NULL;
2221 outbuf->written = 0;
2223 use = xmlBufUse(buf);
2224 oldalloc = xmlBufGetAllocationScheme(buf);
2225 xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
2226 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
2227 xmlBufSetAllocationScheme(buf, oldalloc);
2228 xmlFree(outbuf);
2229 ret = xmlBufUse(buf) - use;
2230 return (ret);
2234 * xmlElemDump:
2235 * @f: the FILE * for the output
2236 * @doc: the document
2237 * @cur: the current node
2239 * Dump an XML/HTML node, recursive behaviour, children are printed too.
2241 void
2242 xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
2244 xmlOutputBufferPtr outbuf;
2246 xmlInitParser();
2248 if (cur == NULL) {
2249 #ifdef DEBUG_TREE
2250 xmlGenericError(xmlGenericErrorContext,
2251 "xmlElemDump : cur == NULL\n");
2252 #endif
2253 return;
2255 #ifdef DEBUG_TREE
2256 if (doc == NULL) {
2257 xmlGenericError(xmlGenericErrorContext,
2258 "xmlElemDump : doc == NULL\n");
2260 #endif
2262 outbuf = xmlOutputBufferCreateFile(f, NULL);
2263 if (outbuf == NULL)
2264 return;
2265 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
2266 #ifdef LIBXML_HTML_ENABLED
2267 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
2268 #else
2269 xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");
2270 #endif /* LIBXML_HTML_ENABLED */
2271 } else
2272 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
2273 xmlOutputBufferClose(outbuf);
2276 /************************************************************************
2278 * Saving functions front-ends *
2280 ************************************************************************/
2283 * xmlNodeDumpOutput:
2284 * @buf: the XML buffer output
2285 * @doc: the document
2286 * @cur: the current node
2287 * @level: the imbrication level for indenting
2288 * @format: is formatting allowed
2289 * @encoding: an optional encoding string
2291 * Dump an XML node, recursive behaviour, children are printed too.
2292 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2293 * or xmlKeepBlanksDefault(0) was called
2295 void
2296 xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
2297 int level, int format, const char *encoding)
2299 xmlSaveCtxt ctxt;
2300 #ifdef LIBXML_HTML_ENABLED
2301 xmlDtdPtr dtd;
2302 int is_xhtml = 0;
2303 #endif
2305 xmlInitParser();
2307 if ((buf == NULL) || (cur == NULL)) return;
2309 if (encoding == NULL)
2310 encoding = "UTF-8";
2312 memset(&ctxt, 0, sizeof(ctxt));
2313 ctxt.buf = buf;
2314 ctxt.level = level;
2315 ctxt.format = format ? 1 : 0;
2316 ctxt.encoding = (const xmlChar *) encoding;
2317 xmlSaveCtxtInit(&ctxt);
2318 ctxt.options |= XML_SAVE_AS_XML;
2320 #ifdef LIBXML_HTML_ENABLED
2321 dtd = xmlGetIntSubset(doc);
2322 if (dtd != NULL) {
2323 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
2324 if (is_xhtml < 0)
2325 is_xhtml = 0;
2328 if (is_xhtml)
2329 xhtmlNodeDumpOutput(&ctxt, cur);
2330 else
2331 #endif
2332 xmlNodeDumpOutputInternal(&ctxt, cur);
2336 * xmlDocDumpFormatMemoryEnc:
2337 * @out_doc: Document to generate XML text from
2338 * @doc_txt_ptr: Memory pointer for allocated XML text
2339 * @doc_txt_len: Length of the generated XML text
2340 * @txt_encoding: Character encoding to use when generating XML text
2341 * @format: should formatting spaces been added
2343 * Dump the current DOM tree into memory using the character encoding specified
2344 * by the caller. Note it is up to the caller of this function to free the
2345 * allocated memory with xmlFree().
2346 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2347 * or xmlKeepBlanksDefault(0) was called
2350 void
2351 xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
2352 int * doc_txt_len, const char * txt_encoding,
2353 int format) {
2354 xmlSaveCtxt ctxt;
2355 int dummy = 0;
2356 xmlOutputBufferPtr out_buff = NULL;
2357 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
2359 if (doc_txt_len == NULL) {
2360 doc_txt_len = &dummy; /* Continue, caller just won't get length */
2363 if (doc_txt_ptr == NULL) {
2364 *doc_txt_len = 0;
2365 return;
2368 *doc_txt_ptr = NULL;
2369 *doc_txt_len = 0;
2371 if (out_doc == NULL) {
2372 /* No document, no output */
2373 return;
2377 * Validate the encoding value, if provided.
2378 * This logic is copied from xmlSaveFileEnc.
2381 if (txt_encoding == NULL)
2382 txt_encoding = (const char *) out_doc->encoding;
2383 if (txt_encoding != NULL) {
2384 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
2385 if ( conv_hdlr == NULL ) {
2386 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
2387 txt_encoding);
2388 return;
2392 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
2393 xmlSaveErrMemory("creating buffer");
2394 return;
2397 memset(&ctxt, 0, sizeof(ctxt));
2398 ctxt.buf = out_buff;
2399 ctxt.level = 0;
2400 ctxt.format = format ? 1 : 0;
2401 ctxt.encoding = (const xmlChar *) txt_encoding;
2402 xmlSaveCtxtInit(&ctxt);
2403 ctxt.options |= XML_SAVE_AS_XML;
2404 xmlDocContentDumpOutput(&ctxt, out_doc);
2405 xmlOutputBufferFlush(out_buff);
2406 if (out_buff->conv != NULL) {
2407 *doc_txt_len = xmlBufUse(out_buff->conv);
2408 *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->conv), *doc_txt_len);
2409 } else {
2410 *doc_txt_len = xmlBufUse(out_buff->buffer);
2411 *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->buffer),*doc_txt_len);
2413 (void)xmlOutputBufferClose(out_buff);
2415 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
2416 *doc_txt_len = 0;
2417 xmlSaveErrMemory("creating output");
2420 return;
2424 * xmlDocDumpMemory:
2425 * @cur: the document
2426 * @mem: OUT: the memory pointer
2427 * @size: OUT: the memory length
2429 * Dump an XML document in memory and return the #xmlChar * and it's size
2430 * in bytes. It's up to the caller to free the memory with xmlFree().
2431 * The resulting byte array is zero terminated, though the last 0 is not
2432 * included in the returned size.
2434 void
2435 xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
2436 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
2440 * xmlDocDumpFormatMemory:
2441 * @cur: the document
2442 * @mem: OUT: the memory pointer
2443 * @size: OUT: the memory length
2444 * @format: should formatting spaces been added
2447 * Dump an XML document in memory and return the #xmlChar * and it's size.
2448 * It's up to the caller to free the memory with xmlFree().
2449 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2450 * or xmlKeepBlanksDefault(0) was called
2452 void
2453 xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
2454 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
2458 * xmlDocDumpMemoryEnc:
2459 * @out_doc: Document to generate XML text from
2460 * @doc_txt_ptr: Memory pointer for allocated XML text
2461 * @doc_txt_len: Length of the generated XML text
2462 * @txt_encoding: Character encoding to use when generating XML text
2464 * Dump the current DOM tree into memory using the character encoding specified
2465 * by the caller. Note it is up to the caller of this function to free the
2466 * allocated memory with xmlFree().
2469 void
2470 xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
2471 int * doc_txt_len, const char * txt_encoding) {
2472 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
2473 txt_encoding, 0);
2477 * xmlDocFormatDump:
2478 * @f: the FILE*
2479 * @cur: the document
2480 * @format: should formatting spaces been added
2482 * Dump an XML document to an open FILE.
2484 * returns: the number of bytes written or -1 in case of failure.
2485 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2486 * or xmlKeepBlanksDefault(0) was called
2489 xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
2490 xmlSaveCtxt ctxt;
2491 xmlOutputBufferPtr buf;
2492 const char * encoding;
2493 xmlCharEncodingHandlerPtr handler = NULL;
2494 int ret;
2496 if (cur == NULL) {
2497 #ifdef DEBUG_TREE
2498 xmlGenericError(xmlGenericErrorContext,
2499 "xmlDocDump : document == NULL\n");
2500 #endif
2501 return(-1);
2503 encoding = (const char *) cur->encoding;
2505 if (encoding != NULL) {
2506 handler = xmlFindCharEncodingHandler(encoding);
2507 if (handler == NULL) {
2508 xmlFree((char *) cur->encoding);
2509 cur->encoding = NULL;
2510 encoding = NULL;
2513 buf = xmlOutputBufferCreateFile(f, handler);
2514 if (buf == NULL) return(-1);
2515 memset(&ctxt, 0, sizeof(ctxt));
2516 ctxt.buf = buf;
2517 ctxt.level = 0;
2518 ctxt.format = format ? 1 : 0;
2519 ctxt.encoding = (const xmlChar *) encoding;
2520 xmlSaveCtxtInit(&ctxt);
2521 ctxt.options |= XML_SAVE_AS_XML;
2522 xmlDocContentDumpOutput(&ctxt, cur);
2524 ret = xmlOutputBufferClose(buf);
2525 return(ret);
2529 * xmlDocDump:
2530 * @f: the FILE*
2531 * @cur: the document
2533 * Dump an XML document to an open FILE.
2535 * returns: the number of bytes written or -1 in case of failure.
2538 xmlDocDump(FILE *f, xmlDocPtr cur) {
2539 return(xmlDocFormatDump (f, cur, 0));
2543 * xmlSaveFileTo:
2544 * @buf: an output I/O buffer
2545 * @cur: the document
2546 * @encoding: the encoding if any assuming the I/O layer handles the transcoding
2548 * Dump an XML document to an I/O buffer.
2549 * Warning ! This call xmlOutputBufferClose() on buf which is not available
2550 * after this call.
2552 * returns: the number of bytes written or -1 in case of failure.
2555 xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
2556 xmlSaveCtxt ctxt;
2557 int ret;
2559 if (buf == NULL) return(-1);
2560 if (cur == NULL) {
2561 xmlOutputBufferClose(buf);
2562 return(-1);
2564 memset(&ctxt, 0, sizeof(ctxt));
2565 ctxt.buf = buf;
2566 ctxt.level = 0;
2567 ctxt.format = 0;
2568 ctxt.encoding = (const xmlChar *) encoding;
2569 xmlSaveCtxtInit(&ctxt);
2570 ctxt.options |= XML_SAVE_AS_XML;
2571 xmlDocContentDumpOutput(&ctxt, cur);
2572 ret = xmlOutputBufferClose(buf);
2573 return(ret);
2577 * xmlSaveFormatFileTo:
2578 * @buf: an output I/O buffer
2579 * @cur: the document
2580 * @encoding: the encoding if any assuming the I/O layer handles the transcoding
2581 * @format: should formatting spaces been added
2583 * Dump an XML document to an I/O buffer.
2584 * Warning ! This call xmlOutputBufferClose() on buf which is not available
2585 * after this call.
2587 * returns: the number of bytes written or -1 in case of failure.
2590 xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur,
2591 const char *encoding, int format)
2593 xmlSaveCtxt ctxt;
2594 int ret;
2596 if (buf == NULL) return(-1);
2597 if ((cur == NULL) ||
2598 ((cur->type != XML_DOCUMENT_NODE) &&
2599 (cur->type != XML_HTML_DOCUMENT_NODE))) {
2600 xmlOutputBufferClose(buf);
2601 return(-1);
2603 memset(&ctxt, 0, sizeof(ctxt));
2604 ctxt.buf = buf;
2605 ctxt.level = 0;
2606 ctxt.format = format ? 1 : 0;
2607 ctxt.encoding = (const xmlChar *) encoding;
2608 xmlSaveCtxtInit(&ctxt);
2609 ctxt.options |= XML_SAVE_AS_XML;
2610 xmlDocContentDumpOutput(&ctxt, cur);
2611 ret = xmlOutputBufferClose(buf);
2612 return (ret);
2616 * xmlSaveFormatFileEnc:
2617 * @filename: the filename or URL to output
2618 * @cur: the document being saved
2619 * @encoding: the name of the encoding to use or NULL.
2620 * @format: should formatting spaces be added.
2622 * Dump an XML document to a file or an URL.
2624 * Returns the number of bytes written or -1 in case of error.
2625 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2626 * or xmlKeepBlanksDefault(0) was called
2629 xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
2630 const char * encoding, int format ) {
2631 xmlSaveCtxt ctxt;
2632 xmlOutputBufferPtr buf;
2633 xmlCharEncodingHandlerPtr handler = NULL;
2634 int ret;
2636 if (cur == NULL)
2637 return(-1);
2639 if (encoding == NULL)
2640 encoding = (const char *) cur->encoding;
2642 if (encoding != NULL) {
2644 handler = xmlFindCharEncodingHandler(encoding);
2645 if (handler == NULL)
2646 return(-1);
2649 #ifdef LIBXML_ZLIB_ENABLED
2650 if (cur->compression < 0) cur->compression = xmlGetCompressMode();
2651 #endif
2653 * save the content to a temp buffer.
2655 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
2656 if (buf == NULL) return(-1);
2657 memset(&ctxt, 0, sizeof(ctxt));
2658 ctxt.buf = buf;
2659 ctxt.level = 0;
2660 ctxt.format = format ? 1 : 0;
2661 ctxt.encoding = (const xmlChar *) encoding;
2662 xmlSaveCtxtInit(&ctxt);
2663 ctxt.options |= XML_SAVE_AS_XML;
2665 xmlDocContentDumpOutput(&ctxt, cur);
2667 ret = xmlOutputBufferClose(buf);
2668 return(ret);
2673 * xmlSaveFileEnc:
2674 * @filename: the filename (or URL)
2675 * @cur: the document
2676 * @encoding: the name of an encoding (or NULL)
2678 * Dump an XML document, converting it to the given encoding
2680 * returns: the number of bytes written or -1 in case of failure.
2683 xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
2684 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
2688 * xmlSaveFormatFile:
2689 * @filename: the filename (or URL)
2690 * @cur: the document
2691 * @format: should formatting spaces been added
2693 * Dump an XML document to a file. Will use compression if
2694 * compiled in and enabled. If @filename is "-" the stdout file is
2695 * used. If @format is set then the document will be indented on output.
2696 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2697 * or xmlKeepBlanksDefault(0) was called
2699 * returns: the number of bytes written or -1 in case of failure.
2702 xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
2703 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
2707 * xmlSaveFile:
2708 * @filename: the filename (or URL)
2709 * @cur: the document
2711 * Dump an XML document to a file. Will use compression if
2712 * compiled in and enabled. If @filename is "-" the stdout file is
2713 * used.
2714 * returns: the number of bytes written or -1 in case of failure.
2717 xmlSaveFile(const char *filename, xmlDocPtr cur) {
2718 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
2721 #endif /* LIBXML_OUTPUT_ENABLED */
2723 #define bottom_xmlsave
2724 #include "elfgcchack.h"