VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/xmlsave.c

Last change on this file was 104106, checked in by vboxsync, 2 months ago

libxml2-2.9.14: Applied and adjusted our libxml2 changes to 2.9.14. bugref:10640

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

© 2023 Oracle
ContactPrivacy policyTerms of Use