ReactOS  0.4.15-dev-3181-g4acf100
xmlsave.c
Go to the documentation of this file.
1 /*
2  * xmlsave.c: Implementation of the document serializer
3  *
4  * See Copyright for the status of this software.
5  *
6  * daniel@veillard.com
7  */
8 
9 #define IN_LIBXML
10 #include "libxml.h"
11 
12 #include <string.h>
13 #include <libxml/xmlmemory.h>
14 #include <libxml/parserInternals.h>
15 #include <libxml/tree.h>
16 #include <libxml/xmlsave.h>
17 
18 #define MAX_INDENT 60
19 
20 #include <libxml/HTMLtree.h>
21 
22 #include "buf.h"
23 #include "enc.h"
24 #include "save.h"
25 
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 
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 
73 #define TODO \
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;
86  int options;
87  int level;
88  int format;
89  char indent[MAX_INDENT + 1]; /* array for indenting output */
90  int indent_nr;
91  int indent_size;
92  xmlCharEncodingOutputFunc escape; /* used for element content */
93  xmlCharEncodingOutputFunc escapeAttr;/* used for attribute content */
94 };
95 
96 /************************************************************************
97  * *
98  * Output error handlers *
99  * *
100  ************************************************************************/
107 static void
108 xmlSaveErrMemory(const char *extra)
109 {
110  __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
111 }
112 
121 static void
122 xmlSaveErr(int code, xmlNodePtr node, const char *extra)
123 {
124  const char *msg = NULL;
125 
126  switch(code) {
127  case XML_SAVE_NOT_UTF8:
128  msg = "string is not in UTF-8\n";
129  break;
131  msg = "invalid character value\n";
132  break;
134  msg = "unknown encoding %s\n";
135  break;
136  case XML_SAVE_NO_DOCTYPE:
137  msg = "document has no DOCTYPE\n";
138  break;
139  default:
140  msg = "unexpected error number\n";
141  }
142  __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
143 }
144 
145 /************************************************************************
146  * *
147  * Special escaping routines *
148  * *
149  ************************************************************************/
150 static unsigned char *
151 xmlSerializeHexCharRef(unsigned char *out, int val) {
152  unsigned char *ptr;
153 
154  *out++ = '&';
155  *out++ = '#';
156  *out++ = 'x';
157  if (val < 0x10) ptr = out;
158  else if (val < 0x100) ptr = out + 1;
159  else if (val < 0x1000) ptr = out + 2;
160  else if (val < 0x10000) ptr = out + 3;
161  else if (val < 0x100000) ptr = out + 4;
162  else ptr = out + 5;
163  out = ptr + 1;
164  while (val > 0) {
165  switch (val & 0xF) {
166  case 0: *ptr-- = '0'; break;
167  case 1: *ptr-- = '1'; break;
168  case 2: *ptr-- = '2'; break;
169  case 3: *ptr-- = '3'; break;
170  case 4: *ptr-- = '4'; break;
171  case 5: *ptr-- = '5'; break;
172  case 6: *ptr-- = '6'; break;
173  case 7: *ptr-- = '7'; break;
174  case 8: *ptr-- = '8'; break;
175  case 9: *ptr-- = '9'; break;
176  case 0xA: *ptr-- = 'A'; break;
177  case 0xB: *ptr-- = 'B'; break;
178  case 0xC: *ptr-- = 'C'; break;
179  case 0xD: *ptr-- = 'D'; break;
180  case 0xE: *ptr-- = 'E'; break;
181  case 0xF: *ptr-- = 'F'; break;
182  default: *ptr-- = '0'; break;
183  }
184  val >>= 4;
185  }
186  *out++ = ';';
187  *out = 0;
188  return(out);
189 }
190 
206 static int
207 xmlEscapeEntities(unsigned char* out, int *outlen,
208  const xmlChar* in, int *inlen) {
209  unsigned char* outstart = out;
210  const unsigned char* base = in;
211  unsigned char* outend = out + *outlen;
212  const unsigned char* inend;
213  int val;
214 
215  inend = in + (*inlen);
216 
217  while ((in < inend) && (out < outend)) {
218  if (*in == '<') {
219  if (outend - out < 4) break;
220  *out++ = '&';
221  *out++ = 'l';
222  *out++ = 't';
223  *out++ = ';';
224  in++;
225  continue;
226  } else if (*in == '>') {
227  if (outend - out < 4) break;
228  *out++ = '&';
229  *out++ = 'g';
230  *out++ = 't';
231  *out++ = ';';
232  in++;
233  continue;
234  } else if (*in == '&') {
235  if (outend - out < 5) break;
236  *out++ = '&';
237  *out++ = 'a';
238  *out++ = 'm';
239  *out++ = 'p';
240  *out++ = ';';
241  in++;
242  continue;
243  } else if (((*in >= 0x20) && (*in < 0x80)) ||
244  (*in == '\n') || (*in == '\t')) {
245  /*
246  * default case, just copy !
247  */
248  *out++ = *in++;
249  continue;
250  } else if (*in >= 0x80) {
251  /*
252  * We assume we have UTF-8 input.
253  */
254  if (outend - out < 11) break;
255 
256  if (*in < 0xC0) {
257  xmlSaveErr(XML_SAVE_NOT_UTF8, NULL, NULL);
258  in++;
259  goto error;
260  } else if (*in < 0xE0) {
261  if (inend - in < 2) break;
262  val = (in[0]) & 0x1F;
263  val <<= 6;
264  val |= (in[1]) & 0x3F;
265  in += 2;
266  } else if (*in < 0xF0) {
267  if (inend - in < 3) break;
268  val = (in[0]) & 0x0F;
269  val <<= 6;
270  val |= (in[1]) & 0x3F;
271  val <<= 6;
272  val |= (in[2]) & 0x3F;
273  in += 3;
274  } else if (*in < 0xF8) {
275  if (inend - in < 4) break;
276  val = (in[0]) & 0x07;
277  val <<= 6;
278  val |= (in[1]) & 0x3F;
279  val <<= 6;
280  val |= (in[2]) & 0x3F;
281  val <<= 6;
282  val |= (in[3]) & 0x3F;
283  in += 4;
284  } else {
285  xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
286  in++;
287  goto error;
288  }
289  if (!IS_CHAR(val)) {
290  xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
291  in++;
292  goto error;
293  }
294 
295  /*
296  * We could do multiple things here. Just save as a char ref
297  */
298  out = xmlSerializeHexCharRef(out, val);
299  } else if (IS_BYTE_CHAR(*in)) {
300  if (outend - out < 6) break;
301  out = xmlSerializeHexCharRef(out, *in++);
302  } else {
304  "xmlEscapeEntities : char out of range\n");
305  in++;
306  goto error;
307  }
308  }
309  *outlen = out - outstart;
310  *inlen = in - base;
311  return(0);
312 error:
313  *outlen = out - outstart;
314  *inlen = in - base;
315  return(-1);
316 }
317 
318 /************************************************************************
319  * *
320  * Allocation and deallocation *
321  * *
322  ************************************************************************/
329 static void
330 xmlSaveCtxtInit(xmlSaveCtxtPtr ctxt)
331 {
332  int i;
333  int len;
334 
335  if (ctxt == NULL) return;
336  if ((ctxt->encoding == NULL) && (ctxt->escape == NULL))
337  ctxt->escape = xmlEscapeEntities;
339  if ((xmlTreeIndentString == NULL) || (len == 0)) {
340  memset(&ctxt->indent[0], 0, MAX_INDENT + 1);
341  } else {
342  ctxt->indent_size = len;
343  ctxt->indent_nr = MAX_INDENT / ctxt->indent_size;
344  for (i = 0;i < ctxt->indent_nr;i++)
345  memcpy(&ctxt->indent[i * ctxt->indent_size], xmlTreeIndentString,
346  ctxt->indent_size);
347  ctxt->indent[ctxt->indent_nr * ctxt->indent_size] = 0;
348  }
349 
350  if (xmlSaveNoEmptyTags) {
351  ctxt->options |= XML_SAVE_NO_EMPTY;
352  }
353 }
354 
360 static void
361 xmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt)
362 {
363  if (ctxt == NULL) return;
364  if (ctxt->encoding != NULL)
365  xmlFree((char *) ctxt->encoding);
366  if (ctxt->buf != NULL)
367  xmlOutputBufferClose(ctxt->buf);
368  xmlFree(ctxt);
369 }
370 
378 static xmlSaveCtxtPtr
379 xmlNewSaveCtxt(const char *encoding, int options)
380 {
381  xmlSaveCtxtPtr ret;
382 
383  ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt));
384  if (ret == NULL) {
385  xmlSaveErrMemory("creating saving context");
386  return ( NULL );
387  }
388  memset(ret, 0, sizeof(xmlSaveCtxt));
389 
390  if (encoding != NULL) {
392  if (ret->handler == NULL) {
394  xmlFreeSaveCtxt(ret);
395  return(NULL);
396  }
397  ret->encoding = xmlStrdup((const xmlChar *)encoding);
398  ret->escape = NULL;
399  }
400  xmlSaveCtxtInit(ret);
401 
402  /*
403  * Use the options
404  */
405 
406  /* Re-check this option as it may already have been set */
407  if ((ret->options & XML_SAVE_NO_EMPTY) && ! (options & XML_SAVE_NO_EMPTY)) {
408  options |= XML_SAVE_NO_EMPTY;
409  }
410 
411  ret->options = options;
412  if (options & XML_SAVE_FORMAT)
413  ret->format = 1;
414  else if (options & XML_SAVE_WSNONSIG)
415  ret->format = 2;
416 
417  return(ret);
418 }
419 
420 /************************************************************************
421  * *
422  * Dumping XML tree content to a simple buffer *
423  * *
424  ************************************************************************/
433 static void
434 xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr)
435 {
436  xmlNodePtr children;
437 
438  children = attr->children;
439  while (children != NULL) {
440  switch (children->type) {
441  case XML_TEXT_NODE:
442  xmlBufAttrSerializeTxtContent(buf->buffer, attr->doc,
443  attr, children->content);
444  break;
445  case XML_ENTITY_REF_NODE:
446  xmlBufAdd(buf->buffer, BAD_CAST "&", 1);
447  xmlBufAdd(buf->buffer, children->name,
448  xmlStrlen(children->name));
449  xmlBufAdd(buf->buffer, BAD_CAST ";", 1);
450  break;
451  default:
452  /* should not happen unless we have a badly built tree */
453  break;
454  }
455  children = children->next;
456  }
457 }
458 
466 void
467 xmlBufDumpNotationTable(xmlBufPtr buf, xmlNotationTablePtr table) {
469 
471  if (buffer == NULL) {
472  /*
473  * TODO set the error in buf
474  */
475  return;
476  }
477  xmlDumpNotationTable(buffer, table);
479 }
480 
489 void
490 xmlBufDumpElementDecl(xmlBufPtr buf, xmlElementPtr elem) {
492 
494  if (buffer == NULL) {
495  /*
496  * TODO set the error in buf
497  */
498  return;
499  }
500  xmlDumpElementDecl(buffer, elem);
502 }
503 
512 void
513 xmlBufDumpAttributeDecl(xmlBufPtr buf, xmlAttributePtr attr) {
515 
517  if (buffer == NULL) {
518  /*
519  * TODO set the error in buf
520  */
521  return;
522  }
523  xmlDumpAttributeDecl(buffer, attr);
525 }
526 
534 void
535 xmlBufDumpEntityDecl(xmlBufPtr buf, xmlEntityPtr ent) {
537 
539  if (buffer == NULL) {
540  /*
541  * TODO set the error in buf
542  */
543  return;
544  }
545  xmlDumpEntityDecl(buffer, ent);
547 }
548 
549 /************************************************************************
550  * *
551  * Dumping XML tree content to an I/O output buffer *
552  * *
553  ************************************************************************/
554 
555 static int xmlSaveSwitchEncoding(xmlSaveCtxtPtr ctxt, const char *encoding) {
556  xmlOutputBufferPtr buf = ctxt->buf;
557 
558  if ((encoding != NULL) && (buf->encoder == NULL) && (buf->conv == NULL)) {
559  buf->encoder = xmlFindCharEncodingHandler((const char *)encoding);
560  if (buf->encoder == NULL) {
561  xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL,
562  (const char *)encoding);
563  return(-1);
564  }
565  buf->conv = xmlBufCreate();
566  if (buf->conv == NULL) {
567  xmlCharEncCloseFunc(buf->encoder);
568  xmlSaveErrMemory("creating encoding buffer");
569  return(-1);
570  }
571  /*
572  * initialize the state, e.g. if outputting a BOM
573  */
574  xmlCharEncOutput(buf, 1);
575  }
576  return(0);
577 }
578 
579 static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) {
580  xmlOutputBufferPtr buf = ctxt->buf;
581  xmlOutputBufferFlush(buf);
582  xmlCharEncCloseFunc(buf->encoder);
583  xmlBufFree(buf->conv);
584  buf->encoder = NULL;
585  buf->conv = NULL;
586  return(0);
587 }
588 
589 #ifdef LIBXML_HTML_ENABLED
590 static void
591 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
592 #endif
593 static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
594 void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
595 static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur);
596 
604 static void
605 xmlOutputBufferWriteWSNonSig(xmlSaveCtxtPtr ctxt, int extra)
606 {
607  int i;
608  if ((ctxt == NULL) || (ctxt->buf == NULL))
609  return;
610  xmlOutputBufferWrite(ctxt->buf, 1, "\n");
611  for (i = 0; i < (ctxt->level + extra); i += ctxt->indent_nr) {
612  xmlOutputBufferWrite(ctxt->buf, ctxt->indent_size *
613  ((ctxt->level + extra - i) > ctxt->indent_nr ?
614  ctxt->indent_nr : (ctxt->level + extra - i)),
615  ctxt->indent);
616  }
617 }
618 
629 static void
630 xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur, xmlSaveCtxtPtr ctxt) {
631  if ((cur == NULL) || (buf == NULL)) return;
632  if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
633  if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
634  return;
635 
636  if (ctxt != NULL && ctxt->format == 2)
637  xmlOutputBufferWriteWSNonSig(ctxt, 2);
638  else
639  xmlOutputBufferWrite(buf, 1, " ");
640 
641  /* Within the context of an element attributes */
642  if (cur->prefix != NULL) {
643  xmlOutputBufferWrite(buf, 6, "xmlns:");
644  xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
645  } else
646  xmlOutputBufferWrite(buf, 5, "xmlns");
647  xmlOutputBufferWrite(buf, 1, "=");
648  xmlBufWriteQuotedString(buf->buffer, cur->href);
649  }
650 }
651 
660 static void
661 xmlNsDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) {
662  xmlNsDumpOutput(ctxt->buf, cur, ctxt);
663 }
664 
673 static void
674 xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) {
675  while (cur != NULL) {
676  xmlNsDumpOutput(ctxt->buf, cur, ctxt);
677  cur = cur->next;
678  }
679 }
680 
689 void
690 xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
691  while (cur != NULL) {
692  xmlNsDumpOutput(buf, cur, NULL);
693  cur = cur->next;
694  }
695 }
696 
704 static void
705 xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
707  xmlNodePtr cur;
708  int format, level;
709 
710  if (dtd == NULL) return;
711  if ((ctxt == NULL) || (ctxt->buf == NULL))
712  return;
713  buf = ctxt->buf;
714  xmlOutputBufferWrite(buf, 10, "<!DOCTYPE ");
715  xmlOutputBufferWriteString(buf, (const char *)dtd->name);
716  if (dtd->ExternalID != NULL) {
717  xmlOutputBufferWrite(buf, 8, " PUBLIC ");
718  xmlBufWriteQuotedString(buf->buffer, dtd->ExternalID);
719  xmlOutputBufferWrite(buf, 1, " ");
720  xmlBufWriteQuotedString(buf->buffer, dtd->SystemID);
721  } else if (dtd->SystemID != NULL) {
722  xmlOutputBufferWrite(buf, 8, " SYSTEM ");
723  xmlBufWriteQuotedString(buf->buffer, dtd->SystemID);
724  }
725  if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
726  (dtd->attributes == NULL) && (dtd->notations == NULL) &&
727  (dtd->pentities == NULL)) {
728  xmlOutputBufferWrite(buf, 1, ">");
729  return;
730  }
731  xmlOutputBufferWrite(buf, 3, " [\n");
732  /*
733  * Dump the notations first they are not in the DTD children list
734  * Do this only on a standalone DTD or on the internal subset though.
735  */
736  if ((dtd->notations != NULL) && ((dtd->doc == NULL) ||
737  (dtd->doc->intSubset == dtd))) {
738  xmlBufDumpNotationTable(buf->buffer,
740  }
741  format = ctxt->format;
742  level = ctxt->level;
743  ctxt->format = 0;
744  ctxt->level = -1;
745  for (cur = dtd->children; cur != NULL; cur = cur->next) {
746  xmlNodeDumpOutputInternal(ctxt, cur);
747  }
748  ctxt->format = format;
749  ctxt->level = level;
750  xmlOutputBufferWrite(buf, 2, "]>");
751 }
752 
760 static void
761 xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
763 
764  if (cur == NULL) return;
765  buf = ctxt->buf;
766  if (buf == NULL) return;
767  if (ctxt->format == 2)
768  xmlOutputBufferWriteWSNonSig(ctxt, 2);
769  else
770  xmlOutputBufferWrite(buf, 1, " ");
771  if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
772  xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
773  xmlOutputBufferWrite(buf, 1, ":");
774  }
775  xmlOutputBufferWriteString(buf, (const char *)cur->name);
776  xmlOutputBufferWrite(buf, 2, "=\"");
777  xmlAttrSerializeContent(buf, cur);
778  xmlOutputBufferWrite(buf, 1, "\"");
779 }
780 
781 #ifdef LIBXML_HTML_ENABLED
782 
788 static int
789 htmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
790  const xmlChar *oldenc = NULL;
791  const xmlChar *oldctxtenc = ctxt->encoding;
792  const xmlChar *encoding = ctxt->encoding;
793  xmlOutputBufferPtr buf = ctxt->buf;
794  int switched_encoding = 0;
795  xmlDocPtr doc;
796 
797  xmlInitParser();
798 
799  doc = cur->doc;
800  if (doc != NULL) {
801  oldenc = doc->encoding;
802  if (ctxt->encoding != NULL) {
803  doc->encoding = BAD_CAST ctxt->encoding;
804  } else if (doc->encoding != NULL) {
805  encoding = doc->encoding;
806  }
807  }
808 
809  if ((encoding != NULL) && (doc != NULL))
810  htmlSetMetaEncoding(doc, (const xmlChar *) encoding);
811  if ((encoding == NULL) && (doc != NULL))
812  encoding = htmlGetMetaEncoding(doc);
813  if (encoding == NULL)
814  encoding = BAD_CAST "HTML";
815  if ((encoding != NULL) && (oldctxtenc == NULL) &&
816  (buf->encoder == NULL) && (buf->conv == NULL)) {
817  if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
818  doc->encoding = oldenc;
819  return(-1);
820  }
821  switched_encoding = 1;
822  }
823  if (ctxt->options & XML_SAVE_FORMAT)
824  htmlNodeDumpFormatOutput(buf, doc, cur,
825  (const char *)encoding, 1);
826  else
827  htmlNodeDumpFormatOutput(buf, doc, cur,
828  (const char *)encoding, 0);
829  /*
830  * Restore the state of the saving context at the end of the document
831  */
832  if ((switched_encoding) && (oldctxtenc == NULL)) {
833  xmlSaveClearEncoding(ctxt);
834  }
835  if (doc != NULL)
836  doc->encoding = oldenc;
837  return(0);
838 }
839 #endif
840 
847 static void
848 xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
849  int format = ctxt->format;
850  xmlNodePtr tmp, root, unformattedNode = NULL;
852  xmlChar *start, *end;
854 
855  if (cur == NULL) return;
856  buf = ctxt->buf;
857 
858  root = cur;
859  while (1) {
860  switch (cur->type) {
861  case XML_DOCUMENT_NODE:
863  xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
864  break;
865 
866  case XML_DTD_NODE:
867  xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
868  break;
869 
871  if (cur->children != NULL) {
872  cur = cur->children;
873  continue;
874  }
875  break;
876 
877  case XML_ELEMENT_DECL:
878  xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
879  break;
880 
881  case XML_ATTRIBUTE_DECL:
882  xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
883  break;
884 
885  case XML_ENTITY_DECL:
886  xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
887  break;
888 
889  case XML_ELEMENT_NODE:
890  if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
891  xmlOutputBufferWrite(buf, ctxt->indent_size *
892  (ctxt->level > ctxt->indent_nr ?
893  ctxt->indent_nr : ctxt->level),
894  ctxt->indent);
895 
896  xmlOutputBufferWrite(buf, 1, "<");
897  if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
898  xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
899  xmlOutputBufferWrite(buf, 1, ":");
900  }
901  xmlOutputBufferWriteString(buf, (const char *)cur->name);
902  if (cur->nsDef)
903  xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
904  for (attr = cur->properties; attr != NULL; attr = attr->next)
905  xmlAttrDumpOutput(ctxt, attr);
906 
907  if (cur->children == NULL) {
908  if ((ctxt->options & XML_SAVE_NO_EMPTY) == 0) {
909  if (ctxt->format == 2)
910  xmlOutputBufferWriteWSNonSig(ctxt, 0);
911  xmlOutputBufferWrite(buf, 2, "/>");
912  } else {
913  if (ctxt->format == 2)
914  xmlOutputBufferWriteWSNonSig(ctxt, 1);
915  xmlOutputBufferWrite(buf, 3, "></");
916  if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
917  xmlOutputBufferWriteString(buf,
918  (const char *)cur->ns->prefix);
919  xmlOutputBufferWrite(buf, 1, ":");
920  }
921  xmlOutputBufferWriteString(buf, (const char *)cur->name);
922  if (ctxt->format == 2)
923  xmlOutputBufferWriteWSNonSig(ctxt, 0);
924  xmlOutputBufferWrite(buf, 1, ">");
925  }
926  } else {
927  if (ctxt->format == 1) {
928  tmp = cur->children;
929  while (tmp != NULL) {
930  if ((tmp->type == XML_TEXT_NODE) ||
931  (tmp->type == XML_CDATA_SECTION_NODE) ||
932  (tmp->type == XML_ENTITY_REF_NODE)) {
933  ctxt->format = 0;
934  unformattedNode = cur;
935  break;
936  }
937  tmp = tmp->next;
938  }
939  }
940  if (ctxt->format == 2)
941  xmlOutputBufferWriteWSNonSig(ctxt, 1);
942  xmlOutputBufferWrite(buf, 1, ">");
943  if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
944  if (ctxt->level >= 0) ctxt->level++;
945  cur = cur->children;
946  continue;
947  }
948 
949  break;
950 
951  case XML_TEXT_NODE:
952  if (cur->content == NULL)
953  break;
954  if (cur->name != xmlStringTextNoenc) {
955  xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
956  } else {
957  /*
958  * Disable escaping, needed for XSLT
959  */
960  xmlOutputBufferWriteString(buf, (const char *) cur->content);
961  }
962  break;
963 
964  case XML_PI_NODE:
965  if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
966  xmlOutputBufferWrite(buf, ctxt->indent_size *
967  (ctxt->level > ctxt->indent_nr ?
968  ctxt->indent_nr : ctxt->level),
969  ctxt->indent);
970 
971  if (cur->content != NULL) {
972  xmlOutputBufferWrite(buf, 2, "<?");
973  xmlOutputBufferWriteString(buf, (const char *)cur->name);
974  if (cur->content != NULL) {
975  if (ctxt->format == 2)
976  xmlOutputBufferWriteWSNonSig(ctxt, 0);
977  else
978  xmlOutputBufferWrite(buf, 1, " ");
979  xmlOutputBufferWriteString(buf,
980  (const char *)cur->content);
981  }
982  xmlOutputBufferWrite(buf, 2, "?>");
983  } else {
984  xmlOutputBufferWrite(buf, 2, "<?");
985  xmlOutputBufferWriteString(buf, (const char *)cur->name);
986  if (ctxt->format == 2)
987  xmlOutputBufferWriteWSNonSig(ctxt, 0);
988  xmlOutputBufferWrite(buf, 2, "?>");
989  }
990  break;
991 
992  case XML_COMMENT_NODE:
993  if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
994  xmlOutputBufferWrite(buf, ctxt->indent_size *
995  (ctxt->level > ctxt->indent_nr ?
996  ctxt->indent_nr : ctxt->level),
997  ctxt->indent);
998 
999  if (cur->content != NULL) {
1000  xmlOutputBufferWrite(buf, 4, "<!--");
1001  xmlOutputBufferWriteString(buf, (const char *)cur->content);
1002  xmlOutputBufferWrite(buf, 3, "-->");
1003  }
1004  break;
1005 
1006  case XML_ENTITY_REF_NODE:
1007  xmlOutputBufferWrite(buf, 1, "&");
1008  xmlOutputBufferWriteString(buf, (const char *)cur->name);
1009  xmlOutputBufferWrite(buf, 1, ";");
1010  break;
1011 
1013  if (cur->content == NULL || *cur->content == '\0') {
1014  xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
1015  } else {
1016  start = end = cur->content;
1017  while (*end != '\0') {
1018  if ((*end == ']') && (*(end + 1) == ']') &&
1019  (*(end + 2) == '>')) {
1020  end = end + 2;
1021  xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1022  xmlOutputBufferWrite(buf, end - start,
1023  (const char *)start);
1024  xmlOutputBufferWrite(buf, 3, "]]>");
1025  start = end;
1026  }
1027  end++;
1028  }
1029  if (start != end) {
1030  xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1031  xmlOutputBufferWriteString(buf, (const char *)start);
1032  xmlOutputBufferWrite(buf, 3, "]]>");
1033  }
1034  }
1035  break;
1036 
1037  case XML_ATTRIBUTE_NODE:
1038  xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
1039  break;
1040 
1041  case XML_NAMESPACE_DECL:
1042  xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
1043  break;
1044 
1045  default:
1046  break;
1047  }
1048 
1049  while (1) {
1050  if (cur == root)
1051  return;
1052  if ((ctxt->format == 1) &&
1053  (cur->type != XML_XINCLUDE_START) &&
1054  (cur->type != XML_XINCLUDE_END))
1055  xmlOutputBufferWrite(buf, 1, "\n");
1056  if (cur->next != NULL) {
1057  cur = cur->next;
1058  break;
1059  }
1060 
1061  /*
1062  * The parent should never be NULL here but we want to handle
1063  * corrupted documents gracefully.
1064  */
1065  if (cur->parent == NULL)
1066  return;
1067  cur = cur->parent;
1068 
1069  if (cur->type == XML_ELEMENT_NODE) {
1070  if (ctxt->level > 0) ctxt->level--;
1071  if ((xmlIndentTreeOutput) && (ctxt->format == 1))
1072  xmlOutputBufferWrite(buf, ctxt->indent_size *
1073  (ctxt->level > ctxt->indent_nr ?
1074  ctxt->indent_nr : ctxt->level),
1075  ctxt->indent);
1076 
1077  xmlOutputBufferWrite(buf, 2, "</");
1078  if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1079  xmlOutputBufferWriteString(buf,
1080  (const char *)cur->ns->prefix);
1081  xmlOutputBufferWrite(buf, 1, ":");
1082  }
1083 
1084  xmlOutputBufferWriteString(buf, (const char *)cur->name);
1085  if (ctxt->format == 2)
1086  xmlOutputBufferWriteWSNonSig(ctxt, 0);
1087  xmlOutputBufferWrite(buf, 1, ">");
1088 
1089  if (cur == unformattedNode) {
1090  ctxt->format = format;
1091  unformattedNode = NULL;
1092  }
1093  }
1094  }
1095  }
1096 }
1097 
1104 static int
1105 xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) {
1106 #ifdef LIBXML_HTML_ENABLED
1107  xmlDtdPtr dtd;
1108  int is_xhtml = 0;
1109 #endif
1110  const xmlChar *oldenc = cur->encoding;
1111  const xmlChar *oldctxtenc = ctxt->encoding;
1112  const xmlChar *encoding = ctxt->encoding;
1113  xmlCharEncodingOutputFunc oldescape = ctxt->escape;
1114  xmlCharEncodingOutputFunc oldescapeAttr = ctxt->escapeAttr;
1115  xmlOutputBufferPtr buf = ctxt->buf;
1116  xmlCharEncoding enc;
1117  int switched_encoding = 0;
1118 
1119  xmlInitParser();
1120 
1121  if ((cur->type != XML_HTML_DOCUMENT_NODE) &&
1122  (cur->type != XML_DOCUMENT_NODE))
1123  return(-1);
1124 
1125  if (ctxt->encoding != NULL) {
1126  cur->encoding = BAD_CAST ctxt->encoding;
1127  } else if (cur->encoding != NULL) {
1128  encoding = cur->encoding;
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=");
1194  if (cur->version != NULL)
1195  xmlBufWriteQuotedString(buf->buffer, cur->version);
1196  else
1197  xmlOutputBufferWrite(buf, 5, "\"1.0\"");
1198  if (encoding != NULL) {
1199  xmlOutputBufferWrite(buf, 10, " encoding=");
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  if ((child->type != XML_XINCLUDE_START) &&
1236  (child->type != XML_XINCLUDE_END))
1237  xmlOutputBufferWrite(buf, 1, "\n");
1238  child = child->next;
1239  }
1240  }
1241  }
1242 
1243  /*
1244  * Restore the state of the saving context at the end of the document
1245  */
1246  if ((switched_encoding) && (oldctxtenc == NULL)) {
1247  xmlSaveClearEncoding(ctxt);
1248  ctxt->escape = oldescape;
1249  ctxt->escapeAttr = oldescapeAttr;
1250  }
1251  cur->encoding = oldenc;
1252  return(0);
1253 }
1254 
1255 #ifdef LIBXML_HTML_ENABLED
1256 /************************************************************************
1257  * *
1258  * Functions specific to XHTML serialization *
1259  * *
1260  ************************************************************************/
1261 
1270 static int
1271 xhtmlIsEmpty(xmlNodePtr node) {
1272  if (node == NULL)
1273  return(-1);
1274  if (node->type != XML_ELEMENT_NODE)
1275  return(0);
1276  if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
1277  return(0);
1278  if (node->children != NULL)
1279  return(0);
1280  switch (node->name[0]) {
1281  case 'a':
1282  if (xmlStrEqual(node->name, BAD_CAST "area"))
1283  return(1);
1284  return(0);
1285  case 'b':
1286  if (xmlStrEqual(node->name, BAD_CAST "br"))
1287  return(1);
1288  if (xmlStrEqual(node->name, BAD_CAST "base"))
1289  return(1);
1290  if (xmlStrEqual(node->name, BAD_CAST "basefont"))
1291  return(1);
1292  return(0);
1293  case 'c':
1294  if (xmlStrEqual(node->name, BAD_CAST "col"))
1295  return(1);
1296  return(0);
1297  case 'f':
1298  if (xmlStrEqual(node->name, BAD_CAST "frame"))
1299  return(1);
1300  return(0);
1301  case 'h':
1302  if (xmlStrEqual(node->name, BAD_CAST "hr"))
1303  return(1);
1304  return(0);
1305  case 'i':
1306  if (xmlStrEqual(node->name, BAD_CAST "img"))
1307  return(1);
1308  if (xmlStrEqual(node->name, BAD_CAST "input"))
1309  return(1);
1310  if (xmlStrEqual(node->name, BAD_CAST "isindex"))
1311  return(1);
1312  return(0);
1313  case 'l':
1314  if (xmlStrEqual(node->name, BAD_CAST "link"))
1315  return(1);
1316  return(0);
1317  case 'm':
1318  if (xmlStrEqual(node->name, BAD_CAST "meta"))
1319  return(1);
1320  return(0);
1321  case 'p':
1322  if (xmlStrEqual(node->name, BAD_CAST "param"))
1323  return(1);
1324  return(0);
1325  }
1326  return(0);
1327 }
1328 
1335 static void
1336 xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
1337  xmlAttrPtr xml_lang = NULL;
1338  xmlAttrPtr lang = NULL;
1339  xmlAttrPtr name = NULL;
1340  xmlAttrPtr id = NULL;
1343 
1344  if (cur == NULL) return;
1345  buf = ctxt->buf;
1346  parent = cur->parent;
1347  while (cur != NULL) {
1348  if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
1349  id = cur;
1350  else
1351  if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
1352  name = cur;
1353  else
1354  if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
1355  lang = cur;
1356  else
1357  if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
1358  (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
1359  xml_lang = cur;
1360  else if ((cur->ns == NULL) &&
1361  ((cur->children == NULL) ||
1362  (cur->children->content == NULL) ||
1363  (cur->children->content[0] == 0)) &&
1364  (htmlIsBooleanAttr(cur->name))) {
1365  if (cur->children != NULL)
1366  xmlFreeNode(cur->children);
1367  cur->children = xmlNewText(cur->name);
1368  if (cur->children != NULL)
1369  cur->children->parent = (xmlNodePtr) cur;
1370  }
1371  xmlAttrDumpOutput(ctxt, cur);
1372  cur = cur->next;
1373  }
1374  /*
1375  * C.8
1376  */
1377  if ((name != NULL) && (id == NULL)) {
1378  if ((parent != NULL) && (parent->name != NULL) &&
1379  ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
1380  (xmlStrEqual(parent->name, BAD_CAST "p")) ||
1381  (xmlStrEqual(parent->name, BAD_CAST "div")) ||
1382  (xmlStrEqual(parent->name, BAD_CAST "img")) ||
1383  (xmlStrEqual(parent->name, BAD_CAST "map")) ||
1384  (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
1385  (xmlStrEqual(parent->name, BAD_CAST "form")) ||
1386  (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
1387  (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
1388  xmlOutputBufferWrite(buf, 5, " id=\"");
1389  xmlAttrSerializeContent(buf, name);
1390  xmlOutputBufferWrite(buf, 1, "\"");
1391  }
1392  }
1393  /*
1394  * C.7.
1395  */
1396  if ((lang != NULL) && (xml_lang == NULL)) {
1397  xmlOutputBufferWrite(buf, 11, " xml:lang=\"");
1398  xmlAttrSerializeContent(buf, lang);
1399  xmlOutputBufferWrite(buf, 1, "\"");
1400  } else
1401  if ((xml_lang != NULL) && (lang == NULL)) {
1402  xmlOutputBufferWrite(buf, 7, " lang=\"");
1403  xmlAttrSerializeContent(buf, xml_lang);
1404  xmlOutputBufferWrite(buf, 1, "\"");
1405  }
1406 }
1407 
1419 static void
1420 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
1421  int format = ctxt->format, addmeta;
1422  xmlNodePtr tmp, root, unformattedNode = NULL;
1423  xmlChar *start, *end;
1424  xmlOutputBufferPtr buf = ctxt->buf;
1425 
1426  if (cur == NULL) return;
1427 
1428  root = cur;
1429  while (1) {
1430  switch (cur->type) {
1431  case XML_DOCUMENT_NODE:
1433  xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
1434  break;
1435 
1436  case XML_NAMESPACE_DECL:
1437  xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
1438  break;
1439 
1440  case XML_DTD_NODE:
1441  xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
1442  break;
1443 
1445  if (cur->children) {
1446  cur = cur->children;
1447  continue;
1448  }
1449  break;
1450 
1451  case XML_ELEMENT_DECL:
1452  xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
1453  break;
1454 
1455  case XML_ATTRIBUTE_DECL:
1456  xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
1457  break;
1458 
1459  case XML_ENTITY_DECL:
1460  xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
1461  break;
1462 
1463  case XML_ELEMENT_NODE:
1464  addmeta = 0;
1465 
1466  if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
1467  xmlOutputBufferWrite(buf, ctxt->indent_size *
1468  (ctxt->level > ctxt->indent_nr ?
1469  ctxt->indent_nr : ctxt->level),
1470  ctxt->indent);
1471 
1472  xmlOutputBufferWrite(buf, 1, "<");
1473  if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1474  xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
1475  xmlOutputBufferWrite(buf, 1, ":");
1476  }
1477 
1478  xmlOutputBufferWriteString(buf, (const char *)cur->name);
1479  if (cur->nsDef)
1480  xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
1481  if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
1482  (cur->ns == NULL) && (cur->nsDef == NULL))) {
1483  /*
1484  * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
1485  */
1486  xmlOutputBufferWriteString(buf,
1487  " xmlns=\"http://www.w3.org/1999/xhtml\"");
1488  }
1489  if (cur->properties != NULL)
1490  xhtmlAttrListDumpOutput(ctxt, cur->properties);
1491 
1492  if ((cur->parent != NULL) &&
1493  (cur->parent->parent == (xmlNodePtr) cur->doc) &&
1494  xmlStrEqual(cur->name, BAD_CAST"head") &&
1495  xmlStrEqual(cur->parent->name, BAD_CAST"html")) {
1496 
1497  tmp = cur->children;
1498  while (tmp != NULL) {
1499  if (xmlStrEqual(tmp->name, BAD_CAST"meta")) {
1500  xmlChar *httpequiv;
1501 
1502  httpequiv = xmlGetProp(tmp, BAD_CAST"http-equiv");
1503  if (httpequiv != NULL) {
1504  if (xmlStrcasecmp(httpequiv,
1505  BAD_CAST"Content-Type") == 0) {
1506  xmlFree(httpequiv);
1507  break;
1508  }
1509  xmlFree(httpequiv);
1510  }
1511  }
1512  tmp = tmp->next;
1513  }
1514  if (tmp == NULL)
1515  addmeta = 1;
1516  }
1517 
1518  if (cur->children == NULL) {
1519  if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
1520  ((xhtmlIsEmpty(cur) == 1) && (addmeta == 0))) {
1521  /*
1522  * C.2. Empty Elements
1523  */
1524  xmlOutputBufferWrite(buf, 3, " />");
1525  } else {
1526  if (addmeta == 1) {
1527  xmlOutputBufferWrite(buf, 1, ">");
1528  if (ctxt->format == 1) {
1529  xmlOutputBufferWrite(buf, 1, "\n");
1530  if (xmlIndentTreeOutput)
1531  xmlOutputBufferWrite(buf, ctxt->indent_size *
1532  (ctxt->level + 1 > ctxt->indent_nr ?
1533  ctxt->indent_nr : ctxt->level + 1),
1534  ctxt->indent);
1535  }
1536  xmlOutputBufferWriteString(buf,
1537  "<meta http-equiv=\"Content-Type\" "
1538  "content=\"text/html; charset=");
1539  if (ctxt->encoding) {
1540  xmlOutputBufferWriteString(buf,
1541  (const char *)ctxt->encoding);
1542  } else {
1543  xmlOutputBufferWrite(buf, 5, "UTF-8");
1544  }
1545  xmlOutputBufferWrite(buf, 4, "\" />");
1546  if (ctxt->format == 1)
1547  xmlOutputBufferWrite(buf, 1, "\n");
1548  } else {
1549  xmlOutputBufferWrite(buf, 1, ">");
1550  }
1551  /*
1552  * C.3. Element Minimization and Empty Element Content
1553  */
1554  xmlOutputBufferWrite(buf, 2, "</");
1555  if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1556  xmlOutputBufferWriteString(buf,
1557  (const char *)cur->ns->prefix);
1558  xmlOutputBufferWrite(buf, 1, ":");
1559  }
1560  xmlOutputBufferWriteString(buf, (const char *)cur->name);
1561  xmlOutputBufferWrite(buf, 1, ">");
1562  }
1563  } else {
1564  xmlOutputBufferWrite(buf, 1, ">");
1565  if (addmeta == 1) {
1566  if (ctxt->format == 1) {
1567  xmlOutputBufferWrite(buf, 1, "\n");
1568  if (xmlIndentTreeOutput)
1569  xmlOutputBufferWrite(buf, ctxt->indent_size *
1570  (ctxt->level + 1 > ctxt->indent_nr ?
1571  ctxt->indent_nr : ctxt->level + 1),
1572  ctxt->indent);
1573  }
1574  xmlOutputBufferWriteString(buf,
1575  "<meta http-equiv=\"Content-Type\" "
1576  "content=\"text/html; charset=");
1577  if (ctxt->encoding) {
1578  xmlOutputBufferWriteString(buf,
1579  (const char *)ctxt->encoding);
1580  } else {
1581  xmlOutputBufferWrite(buf, 5, "UTF-8");
1582  }
1583  xmlOutputBufferWrite(buf, 4, "\" />");
1584  }
1585 
1586  if (ctxt->format == 1) {
1587  tmp = cur->children;
1588  while (tmp != NULL) {
1589  if ((tmp->type == XML_TEXT_NODE) ||
1590  (tmp->type == XML_ENTITY_REF_NODE)) {
1591  unformattedNode = cur;
1592  ctxt->format = 0;
1593  break;
1594  }
1595  tmp = tmp->next;
1596  }
1597  }
1598 
1599  if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
1600  if (ctxt->level >= 0) ctxt->level++;
1601  cur = cur->children;
1602  continue;
1603  }
1604 
1605  break;
1606 
1607  case XML_TEXT_NODE:
1608  if (cur->content == NULL)
1609  break;
1610  if ((cur->name == xmlStringText) ||
1611  (cur->name != xmlStringTextNoenc)) {
1612  xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
1613  } else {
1614  /*
1615  * Disable escaping, needed for XSLT
1616  */
1617  xmlOutputBufferWriteString(buf, (const char *) cur->content);
1618  }
1619  break;
1620 
1621  case XML_PI_NODE:
1622  if (cur->content != NULL) {
1623  xmlOutputBufferWrite(buf, 2, "<?");
1624  xmlOutputBufferWriteString(buf, (const char *)cur->name);
1625  if (cur->content != NULL) {
1626  xmlOutputBufferWrite(buf, 1, " ");
1627  xmlOutputBufferWriteString(buf,
1628  (const char *)cur->content);
1629  }
1630  xmlOutputBufferWrite(buf, 2, "?>");
1631  } else {
1632  xmlOutputBufferWrite(buf, 2, "<?");
1633  xmlOutputBufferWriteString(buf, (const char *)cur->name);
1634  xmlOutputBufferWrite(buf, 2, "?>");
1635  }
1636  break;
1637 
1638  case XML_COMMENT_NODE:
1639  if (cur->content != NULL) {
1640  xmlOutputBufferWrite(buf, 4, "<!--");
1641  xmlOutputBufferWriteString(buf, (const char *)cur->content);
1642  xmlOutputBufferWrite(buf, 3, "-->");
1643  }
1644  break;
1645 
1646  case XML_ENTITY_REF_NODE:
1647  xmlOutputBufferWrite(buf, 1, "&");
1648  xmlOutputBufferWriteString(buf, (const char *)cur->name);
1649  xmlOutputBufferWrite(buf, 1, ";");
1650  break;
1651 
1653  if (cur->content == NULL || *cur->content == '\0') {
1654  xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
1655  } else {
1656  start = end = cur->content;
1657  while (*end != '\0') {
1658  if (*end == ']' && *(end + 1) == ']' &&
1659  *(end + 2) == '>') {
1660  end = end + 2;
1661  xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1662  xmlOutputBufferWrite(buf, end - start,
1663  (const char *)start);
1664  xmlOutputBufferWrite(buf, 3, "]]>");
1665  start = end;
1666  }
1667  end++;
1668  }
1669  if (start != end) {
1670  xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1671  xmlOutputBufferWriteString(buf, (const char *)start);
1672  xmlOutputBufferWrite(buf, 3, "]]>");
1673  }
1674  }
1675  break;
1676 
1677  case XML_ATTRIBUTE_NODE:
1678  xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
1679  break;
1680 
1681  default:
1682  break;
1683  }
1684 
1685  while (1) {
1686  if (cur == root)
1687  return;
1688  if (ctxt->format == 1)
1689  xmlOutputBufferWrite(buf, 1, "\n");
1690  if (cur->next != NULL) {
1691  cur = cur->next;
1692  break;
1693  }
1694 
1695  /*
1696  * The parent should never be NULL here but we want to handle
1697  * corrupted documents gracefully.
1698  */
1699  if (cur->parent == NULL)
1700  return;
1701  cur = cur->parent;
1702 
1703  if (cur->type == XML_ELEMENT_NODE) {
1704  if (ctxt->level > 0) ctxt->level--;
1705  if ((xmlIndentTreeOutput) && (ctxt->format == 1))
1706  xmlOutputBufferWrite(buf, ctxt->indent_size *
1707  (ctxt->level > ctxt->indent_nr ?
1708  ctxt->indent_nr : ctxt->level),
1709  ctxt->indent);
1710 
1711  xmlOutputBufferWrite(buf, 2, "</");
1712  if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1713  xmlOutputBufferWriteString(buf,
1714  (const char *)cur->ns->prefix);
1715  xmlOutputBufferWrite(buf, 1, ":");
1716  }
1717 
1718  xmlOutputBufferWriteString(buf, (const char *)cur->name);
1719  xmlOutputBufferWrite(buf, 1, ">");
1720 
1721  if (cur == unformattedNode) {
1722  ctxt->format = format;
1723  unformattedNode = NULL;
1724  }
1725  }
1726  }
1727  }
1728 }
1729 #endif
1730 
1731 /************************************************************************
1732  * *
1733  * Public entry points *
1734  * *
1735  ************************************************************************/
1736 
1748 xmlSaveCtxtPtr
1749 xmlSaveToFd(int fd, const char *encoding, int options)
1750 {
1751  xmlSaveCtxtPtr ret;
1752 
1753  ret = xmlNewSaveCtxt(encoding, options);
1754  if (ret == NULL) return(NULL);
1755  ret->buf = xmlOutputBufferCreateFd(fd, ret->handler);
1756  if (ret->buf == NULL) {
1757  xmlCharEncCloseFunc(ret->handler);
1758  xmlFreeSaveCtxt(ret);
1759  return(NULL);
1760  }
1761  return(ret);
1762 }
1763 
1776 xmlSaveCtxtPtr
1777 xmlSaveToFilename(const char *filename, const char *encoding, int options)
1778 {
1779  xmlSaveCtxtPtr ret;
1780  int compression = 0; /* TODO handle compression option */
1781 
1782  ret = xmlNewSaveCtxt(encoding, options);
1783  if (ret == NULL) return(NULL);
1784  ret->buf = xmlOutputBufferCreateFilename(filename, ret->handler,
1785  compression);
1786  if (ret->buf == NULL) {
1787  xmlCharEncCloseFunc(ret->handler);
1788  xmlFreeSaveCtxt(ret);
1789  return(NULL);
1790  }
1791  return(ret);
1792 }
1793 
1806 xmlSaveCtxtPtr
1807 xmlSaveToBuffer(xmlBufferPtr buffer, const char *encoding, int options)
1808 {
1809  xmlSaveCtxtPtr ret;
1810 
1811  ret = xmlNewSaveCtxt(encoding, options);
1812  if (ret == NULL) return(NULL);
1813  ret->buf = xmlOutputBufferCreateBuffer(buffer, ret->handler);
1814  if (ret->buf == NULL) {
1815  xmlCharEncCloseFunc(ret->handler);
1816  xmlFreeSaveCtxt(ret);
1817  return(NULL);
1818  }
1819  return(ret);
1820 }
1821 
1835 xmlSaveCtxtPtr
1836 xmlSaveToIO(xmlOutputWriteCallback iowrite,
1837  xmlOutputCloseCallback ioclose,
1838  void *ioctx, const char *encoding, int options)
1839 {
1840  xmlSaveCtxtPtr ret;
1841 
1842  ret = xmlNewSaveCtxt(encoding, options);
1843  if (ret == NULL) return(NULL);
1844  ret->buf = xmlOutputBufferCreateIO(iowrite, ioclose, ioctx, ret->handler);
1845  if (ret->buf == NULL) {
1846  xmlCharEncCloseFunc(ret->handler);
1847  xmlFreeSaveCtxt(ret);
1848  return(NULL);
1849  }
1850  return(ret);
1851 }
1852 
1864 long
1865 xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc)
1866 {
1867  long ret = 0;
1868 
1869  if ((ctxt == NULL) || (doc == NULL)) return(-1);
1870  if (xmlDocContentDumpOutput(ctxt, doc) < 0)
1871  return(-1);
1872  return(ret);
1873 }
1874 
1886 long
1887 xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr cur)
1888 {
1889  long ret = 0;
1890 
1891  if ((ctxt == NULL) || (cur == NULL)) return(-1);
1892 #ifdef LIBXML_HTML_ENABLED
1893  if (ctxt->options & XML_SAVE_XHTML) {
1894  xhtmlNodeDumpOutput(ctxt, cur);
1895  return(ret);
1896  }
1897  if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
1898  (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
1899  ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
1900  (ctxt->options & XML_SAVE_AS_HTML)) {
1901  htmlNodeDumpOutputInternal(ctxt, cur);
1902  return(ret);
1903  }
1904 #endif
1905  xmlNodeDumpOutputInternal(ctxt, cur);
1906  return(ret);
1907 }
1908 
1918 int
1919 xmlSaveFlush(xmlSaveCtxtPtr ctxt)
1920 {
1921  if (ctxt == NULL) return(-1);
1922  if (ctxt->buf == NULL) return(-1);
1923  return(xmlOutputBufferFlush(ctxt->buf));
1924 }
1925 
1935 int
1936 xmlSaveClose(xmlSaveCtxtPtr ctxt)
1937 {
1938  int ret;
1939 
1940  if (ctxt == NULL) return(-1);
1941  ret = xmlSaveFlush(ctxt);
1942  xmlFreeSaveCtxt(ctxt);
1943  return(ret);
1944 }
1945 
1955 int
1956 xmlSaveSetEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
1957 {
1958  if (ctxt == NULL) return(-1);
1959  ctxt->escape = escape;
1960  return(0);
1961 }
1962 
1972 int
1973 xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
1974 {
1975  if (ctxt == NULL) return(-1);
1976  ctxt->escapeAttr = escape;
1977  return(0);
1978 }
1979 
1980 /************************************************************************
1981  * *
1982  * Public entry points based on buffers *
1983  * *
1984  ************************************************************************/
1985 
1995 void
1996 xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc,
1997  xmlAttrPtr attr, const xmlChar * string)
1998 {
1999  xmlChar *base, *cur;
2000 
2001  if (string == NULL)
2002  return;
2003  base = cur = (xmlChar *) string;
2004  while (*cur != 0) {
2005  if (*cur == '\n') {
2006  if (base != cur)
2007  xmlBufAdd(buf, base, cur - base);
2008  xmlBufAdd(buf, BAD_CAST "&#10;", 5);
2009  cur++;
2010  base = cur;
2011  } else if (*cur == '\r') {
2012  if (base != cur)
2013  xmlBufAdd(buf, base, cur - base);
2014  xmlBufAdd(buf, BAD_CAST "&#13;", 5);
2015  cur++;
2016  base = cur;
2017  } else if (*cur == '\t') {
2018  if (base != cur)
2019  xmlBufAdd(buf, base, cur - base);
2020  xmlBufAdd(buf, BAD_CAST "&#9;", 4);
2021  cur++;
2022  base = cur;
2023  } else if (*cur == '"') {
2024  if (base != cur)
2025  xmlBufAdd(buf, base, cur - base);
2026  xmlBufAdd(buf, BAD_CAST "&quot;", 6);
2027  cur++;
2028  base = cur;
2029  } else if (*cur == '<') {
2030  if (base != cur)
2031  xmlBufAdd(buf, base, cur - base);
2032  xmlBufAdd(buf, BAD_CAST "&lt;", 4);
2033  cur++;
2034  base = cur;
2035  } else if (*cur == '>') {
2036  if (base != cur)
2037  xmlBufAdd(buf, base, cur - base);
2038  xmlBufAdd(buf, BAD_CAST "&gt;", 4);
2039  cur++;
2040  base = cur;
2041  } else if (*cur == '&') {
2042  if (base != cur)
2043  xmlBufAdd(buf, base, cur - base);
2044  xmlBufAdd(buf, BAD_CAST "&amp;", 5);
2045  cur++;
2046  base = cur;
2047  } else if ((*cur >= 0x80) && (cur[1] != 0) &&
2048  ((doc == NULL) || (doc->encoding == NULL))) {
2049  /*
2050  * We assume we have UTF-8 content.
2051  */
2052  unsigned char tmp[12];
2053  int val = 0, l = 1;
2054 
2055  if (base != cur)
2056  xmlBufAdd(buf, base, cur - base);
2057  if (*cur < 0xC0) {
2058  xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL);
2059  xmlSerializeHexCharRef(tmp, *cur);
2060  xmlBufAdd(buf, (xmlChar *) tmp, -1);
2061  cur++;
2062  base = cur;
2063  continue;
2064  } else if (*cur < 0xE0) {
2065  val = (cur[0]) & 0x1F;
2066  val <<= 6;
2067  val |= (cur[1]) & 0x3F;
2068  l = 2;
2069  } else if ((*cur < 0xF0) && (cur [2] != 0)) {
2070  val = (cur[0]) & 0x0F;
2071  val <<= 6;
2072  val |= (cur[1]) & 0x3F;
2073  val <<= 6;
2074  val |= (cur[2]) & 0x3F;
2075  l = 3;
2076  } else if ((*cur < 0xF8) && (cur [2] != 0) && (cur[3] != 0)) {
2077  val = (cur[0]) & 0x07;
2078  val <<= 6;
2079  val |= (cur[1]) & 0x3F;
2080  val <<= 6;
2081  val |= (cur[2]) & 0x3F;
2082  val <<= 6;
2083  val |= (cur[3]) & 0x3F;
2084  l = 4;
2085  }
2086  if ((l == 1) || (!IS_CHAR(val))) {
2087  xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL);
2088  xmlSerializeHexCharRef(tmp, *cur);
2089  xmlBufAdd(buf, (xmlChar *) tmp, -1);
2090  cur++;
2091  base = cur;
2092  continue;
2093  }
2094  /*
2095  * We could do multiple things here. Just save
2096  * as a char ref
2097  */
2098  xmlSerializeHexCharRef(tmp, val);
2099  xmlBufAdd(buf, (xmlChar *) tmp, -1);
2100  cur += l;
2101  base = cur;
2102  } else {
2103  cur++;
2104  }
2105  }
2106  if (base != cur)
2107  xmlBufAdd(buf, base, cur - base);
2108 }
2109 
2119 void
2120 xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc,
2121  xmlAttrPtr attr, const xmlChar * string)
2122 {
2123  xmlBufPtr buffer;
2124 
2125  if ((buf == NULL) || (string == NULL))
2126  return;
2128  if (buffer == NULL)
2129  return;
2130  xmlBufAttrSerializeTxtContent(buffer, doc, attr, string);
2132 }
2133 
2150 int
2151 xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
2152  int format)
2153 {
2154  xmlBufPtr buffer;
2155  size_t ret;
2156 
2157  if ((buf == NULL) || (cur == NULL))
2158  return(-1);
2160  if (buffer == NULL)
2161  return(-1);
2162  ret = xmlBufNodeDump(buffer, doc, cur, level, format);
2164  if (ret > INT_MAX)
2165  return(-1);
2166  return((int) ret);
2167 }
2168 
2185 size_t
2186 xmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
2187  int format)
2188 {
2189  size_t use;
2190  int ret;
2191  xmlOutputBufferPtr outbuf;
2192  int oldalloc;
2193 
2194  xmlInitParser();
2195 
2196  if (cur == NULL) {
2197 #ifdef DEBUG_TREE
2199  "xmlNodeDump : node == NULL\n");
2200 #endif
2201  return (-1);
2202  }
2203  if (buf == NULL) {
2204 #ifdef DEBUG_TREE
2206  "xmlNodeDump : buf == NULL\n");
2207 #endif
2208  return (-1);
2209  }
2210  outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2211  if (outbuf == NULL) {
2212  xmlSaveErrMemory("creating buffer");
2213  return (-1);
2214  }
2215  memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
2216  outbuf->buffer = buf;
2217  outbuf->encoder = NULL;
2218  outbuf->writecallback = NULL;
2219  outbuf->closecallback = NULL;
2220  outbuf->context = NULL;
2221  outbuf->written = 0;
2222 
2223  use = xmlBufUse(buf);
2224  oldalloc = xmlBufGetAllocationScheme(buf);
2226  xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
2227  xmlBufSetAllocationScheme(buf, oldalloc);
2228  xmlFree(outbuf);
2229  ret = xmlBufUse(buf) - use;
2230  return (ret);
2231 }
2232 
2241 void
2242 xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
2243 {
2244  xmlOutputBufferPtr outbuf;
2245 
2246  xmlInitParser();
2247 
2248  if (cur == NULL) {
2249 #ifdef DEBUG_TREE
2251  "xmlElemDump : cur == NULL\n");
2252 #endif
2253  return;
2254  }
2255 #ifdef DEBUG_TREE
2256  if (doc == NULL) {
2258  "xmlElemDump : doc == NULL\n");
2259  }
2260 #endif
2261 
2262  outbuf = xmlOutputBufferCreateFile(f, NULL);
2263  if (outbuf == NULL)
2264  return;
2265  if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
2266 #ifdef LIBXML_HTML_ENABLED
2267  htmlNodeDumpOutput(outbuf, doc, cur, NULL);
2268 #else
2269  xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");
2270 #endif /* LIBXML_HTML_ENABLED */
2271  } else
2272  xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
2273  xmlOutputBufferClose(outbuf);
2274 }
2275 
2276 /************************************************************************
2277  * *
2278  * Saving functions front-ends *
2279  * *
2280  ************************************************************************/
2281 
2295 void
2296 xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
2297  int level, int format, const char *encoding)
2298 {
2299  xmlSaveCtxt ctxt;
2300 #ifdef LIBXML_HTML_ENABLED
2301  xmlDtdPtr dtd;
2302  int is_xhtml = 0;
2303 #endif
2304 
2305  xmlInitParser();
2306 
2307  if ((buf == NULL) || (cur == NULL)) return;
2308 
2309  if (encoding == NULL)
2310  encoding = "UTF-8";
2311 
2312  memset(&ctxt, 0, sizeof(ctxt));
2313  ctxt.buf = buf;
2314  ctxt.level = level;
2315  ctxt.format = format ? 1 : 0;
2316  ctxt.encoding = (const xmlChar *) encoding;
2317  xmlSaveCtxtInit(&ctxt);
2318  ctxt.options |= XML_SAVE_AS_XML;
2319 
2320 #ifdef LIBXML_HTML_ENABLED
2321  dtd = xmlGetIntSubset(doc);
2322  if (dtd != NULL) {
2323  is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
2324  if (is_xhtml < 0)
2325  is_xhtml = 0;
2326  }
2327 
2328  if (is_xhtml)
2329  xhtmlNodeDumpOutput(&ctxt, cur);
2330  else
2331 #endif
2332  xmlNodeDumpOutputInternal(&ctxt, cur);
2333 }
2334 
2350 void
2351 xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
2352  int * doc_txt_len, const char * txt_encoding,
2353  int format) {
2354  xmlSaveCtxt ctxt;
2355  int dummy = 0;
2356  xmlOutputBufferPtr out_buff = NULL;
2357  xmlCharEncodingHandlerPtr conv_hdlr = NULL;
2358 
2359  if (doc_txt_len == NULL) {
2360  doc_txt_len = &dummy; /* Continue, caller just won't get length */
2361  }
2362 
2363  if (doc_txt_ptr == NULL) {
2364  *doc_txt_len = 0;
2365  return;
2366  }
2367 
2368  *doc_txt_ptr = NULL;
2369  *doc_txt_len = 0;
2370 
2371  if (out_doc == NULL) {
2372  /* No document, no output */
2373  return;
2374  }
2375 
2376  /*
2377  * Validate the encoding value, if provided.
2378  * This logic is copied from xmlSaveFileEnc.
2379  */
2380 
2381  if (txt_encoding == NULL)
2382  txt_encoding = (const char *) out_doc->encoding;
2383  if (txt_encoding != NULL) {
2384  conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
2385  if ( conv_hdlr == NULL ) {
2386  xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
2387  txt_encoding);
2388  return;
2389  }
2390  }
2391 
2392  if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
2393  xmlSaveErrMemory("creating buffer");
2394  return;
2395  }
2396 
2397  memset(&ctxt, 0, sizeof(ctxt));
2398  ctxt.buf = out_buff;
2399  ctxt.level = 0;
2400  ctxt.format = format ? 1 : 0;
2401  ctxt.encoding = (const xmlChar *) txt_encoding;
2402  xmlSaveCtxtInit(&ctxt);
2403  ctxt.options |= XML_SAVE_AS_XML;
2404  xmlDocContentDumpOutput(&ctxt, out_doc);
2405  xmlOutputBufferFlush(out_buff);
2406  if (out_buff->conv != NULL) {
2407  *doc_txt_len = xmlBufUse(out_buff->conv);
2408  *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->conv), *doc_txt_len);
2409  } else {
2410  *doc_txt_len = xmlBufUse(out_buff->buffer);
2411  *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->buffer),*doc_txt_len);
2412  }
2413  (void)xmlOutputBufferClose(out_buff);
2414 
2415  if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
2416  *doc_txt_len = 0;
2417  xmlSaveErrMemory("creating output");
2418  }
2419 
2420  return;
2421 }
2422 
2434 void
2435 xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
2436  xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
2437 }
2438 
2452 void
2453 xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
2454  xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
2455 }
2456 
2469 void
2470 xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
2471  int * doc_txt_len, const char * txt_encoding) {
2472  xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
2473  txt_encoding, 0);
2474 }
2475 
2488 int
2489 xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
2490  xmlSaveCtxt ctxt;
2492  const char * encoding;
2494  int ret;
2495 
2496  if (cur == NULL) {
2497 #ifdef DEBUG_TREE
2499  "xmlDocDump : document == NULL\n");
2500 #endif
2501  return(-1);
2502  }
2503  encoding = (const char *) cur->encoding;
2504 
2505  if (encoding != NULL) {
2507  if (handler == NULL) {
2508  xmlFree((char *) cur->encoding);
2509  cur->encoding = NULL;
2510  encoding = NULL;
2511  }
2512  }
2513  buf = xmlOutputBufferCreateFile(f, handler);
2514  if (buf == NULL) return(-1);
2515  memset(&ctxt, 0, sizeof(ctxt));
2516  ctxt.buf = buf;
2517  ctxt.level = 0;
2518  ctxt.format = format ? 1 : 0;
2519  ctxt.encoding = (const xmlChar *) encoding;
2520  xmlSaveCtxtInit(&ctxt);
2521  ctxt.options |= XML_SAVE_AS_XML;
2522  xmlDocContentDumpOutput(&ctxt, cur);
2523 
2524  ret = xmlOutputBufferClose(buf);
2525  return(ret);
2526 }
2527 
2537 int
2538 xmlDocDump(FILE *f, xmlDocPtr cur) {
2539  return(xmlDocFormatDump (f, cur, 0));
2540 }
2541 
2554 int
2555 xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
2556  xmlSaveCtxt ctxt;
2557  int ret;
2558 
2559  if (buf == NULL) return(-1);
2560  if (cur == NULL) {
2561  xmlOutputBufferClose(buf);
2562  return(-1);
2563  }
2564  memset(&ctxt, 0, sizeof(ctxt));
2565  ctxt.buf = buf;
2566  ctxt.level = 0;
2567  ctxt.format = 0;
2568  ctxt.encoding = (const xmlChar *) encoding;
2569  xmlSaveCtxtInit(&ctxt);
2570  ctxt.options |= XML_SAVE_AS_XML;
2571  xmlDocContentDumpOutput(&ctxt, cur);
2572  ret = xmlOutputBufferClose(buf);
2573  return(ret);
2574 }
2575 
2589 int
2590 xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur,
2591  const char *encoding, int format)
2592 {
2593  xmlSaveCtxt ctxt;
2594  int ret;
2595 
2596  if (buf == NULL) return(-1);
2597  if ((cur == NULL) ||
2598  ((cur->type != XML_DOCUMENT_NODE) &&
2599  (cur->type != XML_HTML_DOCUMENT_NODE))) {
2600  xmlOutputBufferClose(buf);
2601  return(-1);
2602  }
2603  memset(&ctxt, 0, sizeof(ctxt));
2604  ctxt.buf = buf;
2605  ctxt.level = 0;
2606  ctxt.format = format ? 1 : 0;
2607  ctxt.encoding = (const xmlChar *) encoding;
2608  xmlSaveCtxtInit(&ctxt);
2609  ctxt.options |= XML_SAVE_AS_XML;
2610  xmlDocContentDumpOutput(&ctxt, cur);
2611  ret = xmlOutputBufferClose(buf);
2612  return (ret);
2613 }
2614 
2628 int
2629 xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
2630  const char * encoding, int format ) {
2631  xmlSaveCtxt ctxt;
2634  int ret;
2635 
2636  if (cur == NULL)
2637  return(-1);
2638 
2639  if (encoding == NULL)
2640  encoding = (const char *) cur->encoding;
2641 
2642  if (encoding != NULL) {
2643 
2645  if (handler == NULL)
2646  return(-1);
2647  }
2648 
2649 #ifdef LIBXML_ZLIB_ENABLED
2650  if (cur->compression < 0) cur->compression = xmlGetCompressMode();
2651 #endif
2652  /*
2653  * save the content to a temp buffer.
2654  */
2655  buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
2656  if (buf == NULL) return(-1);
2657  memset(&ctxt, 0, sizeof(ctxt));
2658  ctxt.buf = buf;
2659  ctxt.level = 0;
2660  ctxt.format = format ? 1 : 0;
2661  ctxt.encoding = (const xmlChar *) encoding;
2662  xmlSaveCtxtInit(&ctxt);
2663  ctxt.options |= XML_SAVE_AS_XML;
2664 
2665  xmlDocContentDumpOutput(&ctxt, cur);
2666 
2667  ret = xmlOutputBufferClose(buf);
2668  return(ret);
2669 }
2670 
2671 
2682 int
2683 xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
2684  return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
2685 }
2686 
2701 int
2702 xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
2703  return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
2704 }
2705 
2716 int
2717 xmlSaveFile(const char *filename, xmlDocPtr cur) {
2718  return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
2719 }
2720 
2721 #endif /* LIBXML_OUTPUT_ENABLED */
2722 
2723 #define bottom_xmlsave
2724 #include "elfgcchack.h"
GLint level
Definition: gl.h:1546
xmlElementType type
Definition: tree.h:553
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
XMLPUBFUN xmlCharEncoding XMLCALL xmlParseCharEncoding(const char *name)
Definition: encoding.c:1160
static const WCHAR indent[]
Definition: object.c:1156
XMLPUBFUN xmlChar *XMLCALL xmlBufContent(const xmlBuf *buf)
Definition: buf.c:582
#define INT_MAX
Definition: limits.h:40
#define error(str)
Definition: mkdosfs.c:1605
const xmlChar * name
Definition: tree.h:492
#define XHTML_TRANS_SYSTEM_ID
Definition: xmlsave.c:41
struct _xmlDoc * doc
Definition: tree.h:415
void * notations
Definition: tree.h:418
Definition: tree.h:389
XMLPUBFUN xmlChar *XMLCALL xmlStrndup(const xmlChar *cur, int len)
Definition: xmlstring.c:41
XMLPUBFUN void XMLCALL xmlInitParser(void)
Definition: parser.c:14670
int xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID)
Definition: xmlsave.c:55
XMLPUBFUN int XMLCALL xmlStrlen(const xmlChar *str)
Definition: xmlstring.c:425
struct _root root
XMLPUBFUN xmlChar *XMLCALL xmlGetProp(const xmlNode *node, const xmlChar *name)
#define MAX_INDENT
Definition: xmlsave.c:18
#define XHTML_TRANS_PUBLIC_ID
Definition: xmlsave.c:39
xmlBufPtr xmlBufFromBuffer(xmlBufferPtr buffer)
Definition: buf.c:1167
GLuint buffer
Definition: glext.h:5915
static int fd
Definition: io.c:51
xmlCharEncoding
Definition: encoding.h:58
XMLPUBVAR int xmlIndentTreeOutput
Definition: globals.h:387
if(dx==0 &&dy==0)
Definition: linetemp.h:174
const char * filename
Definition: ioapi.h:135
void * attributes
Definition: tree.h:420
static HWND child
Definition: cursoricon.c:298
XMLPUBFUN xmlBufferPtr XMLCALL xmlBufferCreate(void)
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
Definition: tree.h:406
struct _xmlOutputBuffer xmlOutputBuffer
Definition: tree.h:31
Definition: buf.c:43
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint base
Definition: 3dtext.c:35
const xmlChar * name
Definition: tree.h:409
xmlOutputBuffer * xmlOutputBufferPtr
Definition: tree.h:32
XMLPUBFUN int XMLCALL xmlGetCompressMode(void)
int(* xmlCharEncodingOutputFunc)(unsigned char *out, int *outlen, const unsigned char *in, int *inlen)
Definition: encoding.h:123
static size_t elem
Definition: string.c:68
#define IS_CHAR(c)
#define XHTML_STRICT_SYSTEM_ID
Definition: xmlsave.c:33
static PVOID ptr
Definition: dispmode.c:27
XMLPUBVAR const xmlChar xmlStringText[]
XMLPUBVAR xmlGenericErrorFunc xmlGenericError
Definition: globals.h:346
#define XML_LOCAL_NAMESPACE
Definition: tree.h:374
void xmlBufFree(xmlBufPtr buf)
Definition: buf.c:329
xmlNode * xmlNodePtr
Definition: tree.h:488
#define BAD_CAST
Definition: xmlstring.h:35
XMLPUBVAR const char * xmlTreeIndentString
Definition: globals.h:396
int options
Definition: main.c:106
#define XHTML_FRAME_PUBLIC_ID
Definition: xmlsave.c:35
GLuint GLfloat * val
Definition: glext.h:7180
const xmlChar * ExternalID
Definition: tree.h:422
r l[0]
Definition: byte_order.h:167
static const WCHAR lang[]
Definition: wbemdisp.c:287
GLfloat f
Definition: glext.h:7540
GLsizeiptr size
Definition: glext.h:5919
Definition: id3.c:95
r parent
Definition: btrfs.c:2944
void * elements
Definition: tree.h:419
#define IS_BYTE_CHAR(c)
static FILE * out
Definition: regtests2xml.c:44
int xmlCharEncOutput(xmlOutputBufferPtr output, int init)
XMLPUBFUN int XMLCALL xmlCharEncCloseFunc(xmlCharEncodingHandler *handler)
Definition: encoding.c:2780
XMLPUBVAR xmlFreeFunc xmlFree
Definition: globals.h:250
int xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len)
Definition: buf.c:868
Definition: cookie.c:201
xmlChar * content
Definition: tree.h:502
const xmlChar * SystemID
Definition: tree.h:423
void * entities
Definition: tree.h:421
GLuint GLuint end
Definition: gl.h:1545
Definition: tree.h:489
int ret
xmlBufferPtr xmlBufBackToBuffer(xmlBufPtr buf)
Definition: buf.c:1204
__u8 attr
Definition: mkdosfs.c:359
XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL xmlFindCharEncodingHandler(const char *name)
Definition: encoding.c:1660
_In_ fcb _In_ chunk _In_ uint64_t _In_ uint64_t _In_ bool _In_opt_ void _In_opt_ PIRP _In_ LIST_ENTRY _In_ uint8_t compression
Definition: btrfs_drv.h:1357
unsigned char xmlChar
Definition: xmlstring.h:28
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
xmlBufPtr xmlBufCreate(void)
Definition: buf.c:122
Definition: inflate.c:139
const xmlChar * encoding
Definition: tree.h:574
xmlElementType type
Definition: tree.h:491
ed encoding
Definition: write.c:2825
FxCollectionEntry * cur
#define XHTML_STRICT_PUBLIC_ID
Definition: xmlsave.c:31
int xmlBufGetAllocationScheme(xmlBufPtr buf)
Definition: buf.c:267
struct _xmlNode * children
Definition: tree.h:410
#define XHTML_NS_NAME
Definition: xmlsave.c:44
XMLPUBVAR int xmlSaveNoEmptyTags
Definition: globals.h:458
int xmlBufSetAllocationScheme(xmlBufPtr buf, xmlBufferAllocationScheme scheme)
Definition: buf.c:288
XMLPUBFUN xmlNodePtr XMLCALL xmlNewText(const xmlChar *content)
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLuint in
Definition: glext.h:9616
struct _xmlNode * next
Definition: tree.h:496
GLuint start
Definition: gl.h:1545
unsigned char dummy
Definition: maze.c:118
XMLPUBVAR const xmlChar xmlStringTextNoenc[]
#define NULL
Definition: types.h:112
XMLPUBVAR xmlMallocFunc xmlMalloc
Definition: globals.h:247
Definition: tree.h:551
XMLPUBFUN xmlDtdPtr XMLCALL xmlGetIntSubset(const xmlDoc *doc)
XMLPUBFUN void XMLCALL xmlFreeNode(xmlNodePtr cur)
int xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer)
Definition: buf.c:1259
static WCHAR escape[]
Definition: url.c:36
#define msg(x)
Definition: auth_time.c:54
Definition: mem.c:156
Definition: tree.h:434
Definition: name.c:38
#define XHTML_FRAME_SYSTEM_ID
Definition: xmlsave.c:37
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
UINT(* handler)(MSIPACKAGE *)
Definition: action.c:7786
XMLPUBFUN int XMLCALL xmlStrEqual(const xmlChar *str1, const xmlChar *str2)
Definition: xmlstring.c:159
#define memset(x, y, z)
Definition: compat.h:39
int xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string)
Definition: buf.c:1111
void * pentities
Definition: tree.h:424
XMLPUBFUN int XMLCALL xmlStrcasecmp(const xmlChar *str1, const xmlChar *str2)
Definition: xmlstring.c:274
XMLPUBFUN size_t XMLCALL xmlBufUse(const xmlBufPtr buf)
Definition: buf.c:687
XMLPUBFUN xmlChar *XMLCALL xmlStrdup(const xmlChar *cur)
Definition: xmlstring.c:66
Definition: dlist.c:348
XMLPUBVAR void * xmlGenericErrorContext
Definition: globals.h:362