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