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