1 /* 2 * xmlsave.c: Implemetation of the document serializer 3 * 4 * See Copyright for the status of this software. 5 * 6 * daniel@veillard.com 7 */ 8 9 #define IN_LIBXML 10 #include "libxml.h" 11 12 #include <string.h> 13 #include <libxml/xmlmemory.h> 14 #include <libxml/parserInternals.h> 15 #include <libxml/tree.h> 16 #include <libxml/xmlsave.h> 17 18 #define MAX_INDENT 60 19 20 #include <libxml/HTMLtree.h> 21 22 #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 /** 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 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; 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 * * 99 * Output error handlers * 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); 217 218 while ((in < inend) && (out < outend)) { 219 if (*in == '<') { 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 */ 255 if (outend - out < 11) break; 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 * * 423 * Dumping XML tree content to a simple buffer * 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: 443 xmlBufAttrSerializeTxtContent(buf->buffer, attr->doc, 444 attr, children->content); 445 break; 446 case XML_ENTITY_REF_NODE: 447 xmlBufAdd(buf->buffer, BAD_CAST "&", 1); 448 xmlBufAdd(buf->buffer, children->name, 449 xmlStrlen(children->name)); 450 xmlBufAdd(buf->buffer, BAD_CAST ";", 1); 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 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 550 /************************************************************************ 551 * * 552 * Dumping XML tree content to an I/O output buffer * 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 } 566 buf->conv = xmlBufCreate(); 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 */ 575 xmlCharEncOutput(buf, 1); 576 } 577 return(0); 578 } 579 580 static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) { 581 xmlOutputBufferPtr buf = ctxt->buf; 582 xmlOutputBufferFlush(buf); 583 xmlCharEncCloseFunc(buf->encoder); 584 xmlBufFree(buf->conv); 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, "="); 650 xmlBufWriteQuotedString(buf->buffer, cur->href); 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 703 * 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 "); 720 xmlBufWriteQuotedString(buf->buffer, dtd->ExternalID); 721 xmlOutputBufferWrite(buf, 1, " "); 722 xmlBufWriteQuotedString(buf->buffer, dtd->SystemID); 723 } else if (dtd->SystemID != NULL) { 724 xmlOutputBufferWrite(buf, 8, " SYSTEM "); 725 xmlBufWriteQuotedString(buf->buffer, dtd->SystemID); 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))) { 740 xmlBufDumpNotationTable(buf->buffer, 741 (xmlNotationTablePtr) dtd->notations); 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 * 822 (ctxt->level > ctxt->indent_nr ? 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) { 939 xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur); 940 return; 941 } 942 if (cur->type == XML_ATTRIBUTE_DECL) { 943 xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); 944 return; 945 } 946 if (cur->type == XML_ENTITY_DECL) { 947 xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); 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 * 1078 (ctxt->level > ctxt->indent_nr ? 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 } 1127 1128 if (((cur->type == XML_HTML_DOCUMENT_NODE) && 1129 ((ctxt->options & XML_SAVE_AS_XML) == 0) && 1130 ((ctxt->options & XML_SAVE_XHTML) == 0)) || 1131 (ctxt->options & XML_SAVE_AS_HTML)) { 1132 #ifdef LIBXML_HTML_ENABLED 1133 if (encoding != NULL) 1134 htmlSetMetaEncoding(cur, (const xmlChar *) encoding); 1135 if (encoding == NULL) 1136 encoding = htmlGetMetaEncoding(cur); 1137 if (encoding == NULL) 1138 encoding = BAD_CAST "HTML"; 1139 if ((encoding != NULL) && (oldctxtenc == NULL) && 1140 (buf->encoder == NULL) && (buf->conv == NULL)) { 1141 if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) { 1142 cur->encoding = oldenc; 1143 return(-1); 1144 } 1145 } 1146 if (ctxt->options & XML_SAVE_FORMAT) 1147 htmlDocContentDumpFormatOutput(buf, cur, 1148 (const char *)encoding, 1); 1149 else 1150 htmlDocContentDumpFormatOutput(buf, cur, 1151 (const char *)encoding, 0); 1152 if (ctxt->encoding != NULL) 1153 cur->encoding = oldenc; 1154 return(0); 1155 #else 1156 return(-1); 1157 #endif 1158 } else if ((cur->type == XML_DOCUMENT_NODE) || 1159 (ctxt->options & XML_SAVE_AS_XML) || 1160 (ctxt->options & XML_SAVE_XHTML)) { 1161 enc = xmlParseCharEncoding((const char*) encoding); 1162 if ((encoding != NULL) && (oldctxtenc == NULL) && 1163 (buf->encoder == NULL) && (buf->conv == NULL) && 1164 ((ctxt->options & XML_SAVE_NO_DECL) == 0)) { 1165 if ((enc != XML_CHAR_ENCODING_UTF8) && 1166 (enc != XML_CHAR_ENCODING_NONE) && 1167 (enc != XML_CHAR_ENCODING_ASCII)) { 1168 /* 1169 * we need to switch to this encoding but just for this 1170 * document since we output the XMLDecl the conversion 1171 * must be done to not generate not well formed documents. 1172 */ 1173 if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) { 1174 cur->encoding = oldenc; 1175 return(-1); 1176 } 1177 switched_encoding = 1; 1178 } 1179 if (ctxt->escape == xmlEscapeEntities) 1180 ctxt->escape = NULL; 1181 if (ctxt->escapeAttr == xmlEscapeEntities) 1182 ctxt->escapeAttr = NULL; 1183 } 1184 1185 1186 /* 1187 * Save the XML declaration 1188 */ 1189 if ((ctxt->options & XML_SAVE_NO_DECL) == 0) { 1190 xmlOutputBufferWrite(buf, 14, "<?xml version="); 1191 if (cur->version != NULL) 1192 xmlBufWriteQuotedString(buf->buffer, cur->version); 1193 else 1194 xmlOutputBufferWrite(buf, 5, "\"1.0\""); 1195 if (encoding != NULL) { 1196 xmlOutputBufferWrite(buf, 10, " encoding="); 1197 xmlBufWriteQuotedString(buf->buffer, (xmlChar *) encoding); 1198 } 1199 switch (cur->standalone) { 1200 case 0: 1201 xmlOutputBufferWrite(buf, 16, " standalone=\"no\""); 1202 break; 1203 case 1: 1204 xmlOutputBufferWrite(buf, 17, " standalone=\"yes\""); 1205 break; 1206 } 1207 xmlOutputBufferWrite(buf, 3, "?>\n"); 1208 } 1209 1210 #ifdef LIBXML_HTML_ENABLED 1211 if (ctxt->options & XML_SAVE_XHTML) 1212 is_xhtml = 1; 1213 if ((ctxt->options & XML_SAVE_NO_XHTML) == 0) { 1214 dtd = xmlGetIntSubset(cur); 1215 if (dtd != NULL) { 1216 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID); 1217 if (is_xhtml < 0) is_xhtml = 0; 1218 } 1219 } 1220 #endif 1221 if (cur->children != NULL) { 1222 xmlNodePtr child = cur->children; 1223 1224 while (child != NULL) { 1225 ctxt->level = 0; 1226 #ifdef LIBXML_HTML_ENABLED 1227 if (is_xhtml) 1228 xhtmlNodeDumpOutput(ctxt, child); 1229 else 1230 #endif 1231 xmlNodeDumpOutputInternal(ctxt, child); 1232 xmlOutputBufferWrite(buf, 1, "\n"); 1233 child = child->next; 1234 } 1235 } 1236 } 1237 1238 /* 1239 * Restore the state of the saving context at the end of the document 1240 */ 1241 if ((switched_encoding) && (oldctxtenc == NULL)) { 1242 xmlSaveClearEncoding(ctxt); 1243 ctxt->escape = oldescape; 1244 ctxt->escapeAttr = oldescapeAttr; 1245 } 1246 cur->encoding = oldenc; 1247 return(0); 1248 } 1249 1250 #ifdef LIBXML_HTML_ENABLED 1251 /************************************************************************ 1252 * * 1253 * Functions specific to XHTML serialization * 1254 * * 1255 ************************************************************************/ 1256 1257 /** 1258 * xhtmlIsEmpty: 1259 * @node: the node 1260 * 1261 * Check if a node is an empty xhtml node 1262 * 1263 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error 1264 */ 1265 static int 1266 xhtmlIsEmpty(xmlNodePtr node) { 1267 if (node == NULL) 1268 return(-1); 1269 if (node->type != XML_ELEMENT_NODE) 1270 return(0); 1271 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME))) 1272 return(0); 1273 if (node->children != NULL) 1274 return(0); 1275 switch (node->name[0]) { 1276 case 'a': 1277 if (xmlStrEqual(node->name, BAD_CAST "area")) 1278 return(1); 1279 return(0); 1280 case 'b': 1281 if (xmlStrEqual(node->name, BAD_CAST "br")) 1282 return(1); 1283 if (xmlStrEqual(node->name, BAD_CAST "base")) 1284 return(1); 1285 if (xmlStrEqual(node->name, BAD_CAST "basefont")) 1286 return(1); 1287 return(0); 1288 case 'c': 1289 if (xmlStrEqual(node->name, BAD_CAST "col")) 1290 return(1); 1291 return(0); 1292 case 'f': 1293 if (xmlStrEqual(node->name, BAD_CAST "frame")) 1294 return(1); 1295 return(0); 1296 case 'h': 1297 if (xmlStrEqual(node->name, BAD_CAST "hr")) 1298 return(1); 1299 return(0); 1300 case 'i': 1301 if (xmlStrEqual(node->name, BAD_CAST "img")) 1302 return(1); 1303 if (xmlStrEqual(node->name, BAD_CAST "input")) 1304 return(1); 1305 if (xmlStrEqual(node->name, BAD_CAST "isindex")) 1306 return(1); 1307 return(0); 1308 case 'l': 1309 if (xmlStrEqual(node->name, BAD_CAST "link")) 1310 return(1); 1311 return(0); 1312 case 'm': 1313 if (xmlStrEqual(node->name, BAD_CAST "meta")) 1314 return(1); 1315 return(0); 1316 case 'p': 1317 if (xmlStrEqual(node->name, BAD_CAST "param")) 1318 return(1); 1319 return(0); 1320 } 1321 return(0); 1322 } 1323 1324 /** 1325 * xhtmlAttrListDumpOutput: 1326 * @cur: the first attribute pointer 1327 * 1328 * Dump a list of XML attributes 1329 */ 1330 static void 1331 xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { 1332 xmlAttrPtr xml_lang = NULL; 1333 xmlAttrPtr lang = NULL; 1334 xmlAttrPtr name = NULL; 1335 xmlAttrPtr id = NULL; 1336 xmlNodePtr parent; 1337 xmlOutputBufferPtr buf; 1338 1339 if (cur == NULL) return; 1340 buf = ctxt->buf; 1341 parent = cur->parent; 1342 while (cur != NULL) { 1343 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id"))) 1344 id = cur; 1345 else 1346 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name"))) 1347 name = cur; 1348 else 1349 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang"))) 1350 lang = cur; 1351 else 1352 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) && 1353 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml"))) 1354 xml_lang = cur; 1355 else if ((cur->ns == NULL) && 1356 ((cur->children == NULL) || 1357 (cur->children->content == NULL) || 1358 (cur->children->content[0] == 0)) && 1359 (htmlIsBooleanAttr(cur->name))) { 1360 if (cur->children != NULL) 1361 xmlFreeNode(cur->children); 1362 cur->children = xmlNewText(cur->name); 1363 if (cur->children != NULL) 1364 cur->children->parent = (xmlNodePtr) cur; 1365 } 1366 xmlAttrDumpOutput(ctxt, cur); 1367 cur = cur->next; 1368 } 1369 /* 1370 * C.8 1371 */ 1372 if ((name != NULL) && (id == NULL)) { 1373 if ((parent != NULL) && (parent->name != NULL) && 1374 ((xmlStrEqual(parent->name, BAD_CAST "a")) || 1375 (xmlStrEqual(parent->name, BAD_CAST "p")) || 1376 (xmlStrEqual(parent->name, BAD_CAST "div")) || 1377 (xmlStrEqual(parent->name, BAD_CAST "img")) || 1378 (xmlStrEqual(parent->name, BAD_CAST "map")) || 1379 (xmlStrEqual(parent->name, BAD_CAST "applet")) || 1380 (xmlStrEqual(parent->name, BAD_CAST "form")) || 1381 (xmlStrEqual(parent->name, BAD_CAST "frame")) || 1382 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) { 1383 xmlOutputBufferWrite(buf, 5, " id=\""); 1384 xmlAttrSerializeContent(buf, name); 1385 xmlOutputBufferWrite(buf, 1, "\""); 1386 } 1387 } 1388 /* 1389 * C.7. 1390 */ 1391 if ((lang != NULL) && (xml_lang == NULL)) { 1392 xmlOutputBufferWrite(buf, 11, " xml:lang=\""); 1393 xmlAttrSerializeContent(buf, lang); 1394 xmlOutputBufferWrite(buf, 1, "\""); 1395 } else 1396 if ((xml_lang != NULL) && (lang == NULL)) { 1397 xmlOutputBufferWrite(buf, 7, " lang=\""); 1398 xmlAttrSerializeContent(buf, xml_lang); 1399 xmlOutputBufferWrite(buf, 1, "\""); 1400 } 1401 } 1402 1403 /** 1404 * xhtmlNodeListDumpOutput: 1405 * @buf: the XML buffer output 1406 * @doc: the XHTML document 1407 * @cur: the first node 1408 * @level: the imbrication level for indenting 1409 * @format: is formatting allowed 1410 * @encoding: an optional encoding string 1411 * 1412 * Dump an XML node list, recursive behaviour, children are printed too. 1413 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 1414 * or xmlKeepBlanksDefault(0) was called 1415 */ 1416 static void 1417 xhtmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { 1418 xmlOutputBufferPtr buf; 1419 1420 if (cur == NULL) return; 1421 buf = ctxt->buf; 1422 while (cur != NULL) { 1423 if ((ctxt->format == 1) && (xmlIndentTreeOutput) && 1424 (cur->type == XML_ELEMENT_NODE)) 1425 xmlOutputBufferWrite(buf, ctxt->indent_size * 1426 (ctxt->level > ctxt->indent_nr ? 1427 ctxt->indent_nr : ctxt->level), 1428 ctxt->indent); 1429 xhtmlNodeDumpOutput(ctxt, cur); 1430 if (ctxt->format == 1) { 1431 xmlOutputBufferWrite(buf, 1, "\n"); 1432 } 1433 cur = cur->next; 1434 } 1435 } 1436 1437 /** 1438 * xhtmlNodeDumpOutput: 1439 * @buf: the XML buffer output 1440 * @doc: the XHTML document 1441 * @cur: the current node 1442 * @level: the imbrication level for indenting 1443 * @format: is formatting allowed 1444 * @encoding: an optional encoding string 1445 * 1446 * Dump an XHTML node, recursive behaviour, children are printed too. 1447 */ 1448 static void 1449 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { 1450 int format, addmeta = 0; 1451 xmlNodePtr tmp; 1452 xmlChar *start, *end; 1453 xmlOutputBufferPtr buf; 1454 1455 if (cur == NULL) return; 1456 if ((cur->type == XML_DOCUMENT_NODE) || 1457 (cur->type == XML_HTML_DOCUMENT_NODE)) { 1458 xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur); 1459 return; 1460 } 1461 if (cur->type == XML_XINCLUDE_START) 1462 return; 1463 if (cur->type == XML_XINCLUDE_END) 1464 return; 1465 if (cur->type == XML_NAMESPACE_DECL) { 1466 xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur); 1467 return; 1468 } 1469 if (cur->type == XML_DTD_NODE) { 1470 xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur); 1471 return; 1472 } 1473 if (cur->type == XML_DOCUMENT_FRAG_NODE) { 1474 xhtmlNodeListDumpOutput(ctxt, cur->children); 1475 return; 1476 } 1477 buf = ctxt->buf; 1478 if (cur->type == XML_ELEMENT_DECL) { 1479 xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur); 1480 return; 1481 } 1482 if (cur->type == XML_ATTRIBUTE_DECL) { 1483 xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); 1484 return; 1485 } 1486 if (cur->type == XML_ENTITY_DECL) { 1487 xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); 1488 return; 1489 } 1490 if (cur->type == XML_TEXT_NODE) { 1491 if (cur->content != NULL) { 1492 if ((cur->name == xmlStringText) || 1493 (cur->name != xmlStringTextNoenc)) { 1494 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape); 1495 } else { 1496 /* 1497 * Disable escaping, needed for XSLT 1498 */ 1499 xmlOutputBufferWriteString(buf, (const char *) cur->content); 1500 } 1501 } 1502 1503 return; 1504 } 1505 if (cur->type == XML_PI_NODE) { 1506 if (cur->content != NULL) { 1507 xmlOutputBufferWrite(buf, 2, "<?"); 1508 xmlOutputBufferWriteString(buf, (const char *)cur->name); 1509 if (cur->content != NULL) { 1510 xmlOutputBufferWrite(buf, 1, " "); 1511 xmlOutputBufferWriteString(buf, (const char *)cur->content); 1512 } 1513 xmlOutputBufferWrite(buf, 2, "?>"); 1514 } else { 1515 xmlOutputBufferWrite(buf, 2, "<?"); 1516 xmlOutputBufferWriteString(buf, (const char *)cur->name); 1517 xmlOutputBufferWrite(buf, 2, "?>"); 1518 } 1519 return; 1520 } 1521 if (cur->type == XML_COMMENT_NODE) { 1522 if (cur->content != NULL) { 1523 xmlOutputBufferWrite(buf, 4, "<!--"); 1524 xmlOutputBufferWriteString(buf, (const char *)cur->content); 1525 xmlOutputBufferWrite(buf, 3, "-->"); 1526 } 1527 return; 1528 } 1529 if (cur->type == XML_ENTITY_REF_NODE) { 1530 xmlOutputBufferWrite(buf, 1, "&"); 1531 xmlOutputBufferWriteString(buf, (const char *)cur->name); 1532 xmlOutputBufferWrite(buf, 1, ";"); 1533 return; 1534 } 1535 if (cur->type == XML_CDATA_SECTION_NODE) { 1536 if (cur->content == NULL || *cur->content == '\0') { 1537 xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>"); 1538 } else { 1539 start = end = cur->content; 1540 while (*end != '\0') { 1541 if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') { 1542 end = end + 2; 1543 xmlOutputBufferWrite(buf, 9, "<![CDATA["); 1544 xmlOutputBufferWrite(buf, end - start, (const char *)start); 1545 xmlOutputBufferWrite(buf, 3, "]]>"); 1546 start = end; 1547 } 1548 end++; 1549 } 1550 if (start != end) { 1551 xmlOutputBufferWrite(buf, 9, "<![CDATA["); 1552 xmlOutputBufferWriteString(buf, (const char *)start); 1553 xmlOutputBufferWrite(buf, 3, "]]>"); 1554 } 1555 } 1556 return; 1557 } 1558 if (cur->type == XML_ATTRIBUTE_NODE) { 1559 xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur); 1560 return; 1561 } 1562 1563 format = ctxt->format; 1564 if (format == 1) { 1565 tmp = cur->children; 1566 while (tmp != NULL) { 1567 if ((tmp->type == XML_TEXT_NODE) || 1568 (tmp->type == XML_ENTITY_REF_NODE)) { 1569 format = 0; 1570 break; 1571 } 1572 tmp = tmp->next; 1573 } 1574 } 1575 xmlOutputBufferWrite(buf, 1, "<"); 1576 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { 1577 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); 1578 xmlOutputBufferWrite(buf, 1, ":"); 1579 } 1580 1581 xmlOutputBufferWriteString(buf, (const char *)cur->name); 1582 if (cur->nsDef) 1583 xmlNsListDumpOutputCtxt(ctxt, cur->nsDef); 1584 if ((xmlStrEqual(cur->name, BAD_CAST "html") && 1585 (cur->ns == NULL) && (cur->nsDef == NULL))) { 1586 /* 1587 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/ 1588 */ 1589 xmlOutputBufferWriteString(buf, 1590 " xmlns=\"http://www.w3.org/1999/xhtml\""); 1591 } 1592 if (cur->properties != NULL) 1593 xhtmlAttrListDumpOutput(ctxt, cur->properties); 1594 1595 if ((cur->type == XML_ELEMENT_NODE) && 1596 (cur->parent != NULL) && 1597 (cur->parent->parent == (xmlNodePtr) cur->doc) && 1598 xmlStrEqual(cur->name, BAD_CAST"head") && 1599 xmlStrEqual(cur->parent->name, BAD_CAST"html")) { 1600 1601 tmp = cur->children; 1602 while (tmp != NULL) { 1603 if (xmlStrEqual(tmp->name, BAD_CAST"meta")) { 1604 xmlChar *httpequiv; 1605 1606 httpequiv = xmlGetProp(tmp, BAD_CAST"http-equiv"); 1607 if (httpequiv != NULL) { 1608 if (xmlStrcasecmp(httpequiv, BAD_CAST"Content-Type") == 0) { 1609 xmlFree(httpequiv); 1610 break; 1611 } 1612 xmlFree(httpequiv); 1613 } 1614 } 1615 tmp = tmp->next; 1616 } 1617 if (tmp == NULL) 1618 addmeta = 1; 1619 } 1620 1621 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) { 1622 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) && 1623 ((xhtmlIsEmpty(cur) == 1) && (addmeta == 0))) { 1624 /* 1625 * C.2. Empty Elements 1626 */ 1627 xmlOutputBufferWrite(buf, 3, " />"); 1628 } else { 1629 if (addmeta == 1) { 1630 xmlOutputBufferWrite(buf, 1, ">"); 1631 if (ctxt->format == 1) { 1632 xmlOutputBufferWrite(buf, 1, "\n"); 1633 if (xmlIndentTreeOutput) 1634 xmlOutputBufferWrite(buf, ctxt->indent_size * 1635 (ctxt->level + 1 > ctxt->indent_nr ? 1636 ctxt->indent_nr : ctxt->level + 1), ctxt->indent); 1637 } 1638 xmlOutputBufferWriteString(buf, 1639 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset="); 1640 if (ctxt->encoding) { 1641 xmlOutputBufferWriteString(buf, (const char *)ctxt->encoding); 1642 } else { 1643 xmlOutputBufferWrite(buf, 5, "UTF-8"); 1644 } 1645 xmlOutputBufferWrite(buf, 4, "\" />"); 1646 if (ctxt->format == 1) 1647 xmlOutputBufferWrite(buf, 1, "\n"); 1648 } else { 1649 xmlOutputBufferWrite(buf, 1, ">"); 1650 } 1651 /* 1652 * C.3. Element Minimization and Empty Element Content 1653 */ 1654 xmlOutputBufferWrite(buf, 2, "</"); 1655 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { 1656 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); 1657 xmlOutputBufferWrite(buf, 1, ":"); 1658 } 1659 xmlOutputBufferWriteString(buf, (const char *)cur->name); 1660 xmlOutputBufferWrite(buf, 1, ">"); 1661 } 1662 return; 1663 } 1664 xmlOutputBufferWrite(buf, 1, ">"); 1665 if (addmeta == 1) { 1666 if (ctxt->format == 1) { 1667 xmlOutputBufferWrite(buf, 1, "\n"); 1668 if (xmlIndentTreeOutput) 1669 xmlOutputBufferWrite(buf, ctxt->indent_size * 1670 (ctxt->level + 1 > ctxt->indent_nr ? 1671 ctxt->indent_nr : ctxt->level + 1), ctxt->indent); 1672 } 1673 xmlOutputBufferWriteString(buf, 1674 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset="); 1675 if (ctxt->encoding) { 1676 xmlOutputBufferWriteString(buf, (const char *)ctxt->encoding); 1677 } else { 1678 xmlOutputBufferWrite(buf, 5, "UTF-8"); 1679 } 1680 xmlOutputBufferWrite(buf, 4, "\" />"); 1681 } 1682 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { 1683 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape); 1684 } 1685 1686 #if 0 1687 /* 1688 * This was removed due to problems with HTML processors. 1689 * See bug #345147. 1690 */ 1691 /* 1692 * 4.8. Script and Style elements 1693 */ 1694 if ((cur->type == XML_ELEMENT_NODE) && 1695 ((xmlStrEqual(cur->name, BAD_CAST "script")) || 1696 (xmlStrEqual(cur->name, BAD_CAST "style"))) && 1697 ((cur->ns == NULL) || 1698 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) { 1699 xmlNodePtr child = cur->children; 1700 1701 while (child != NULL) { 1702 if (child->type == XML_TEXT_NODE) { 1703 if ((xmlStrchr(child->content, '<') == NULL) && 1704 (xmlStrchr(child->content, '&') == NULL) && 1705 (xmlStrstr(child->content, BAD_CAST "]]>") == NULL)) { 1706 /* Nothing to escape, so just output as is... */ 1707 /* FIXME: Should we do something about "--" also? */ 1708 int level = ctxt->level; 1709 int indent = ctxt->format; 1710 1711 ctxt->level = 0; 1712 ctxt->format = 0; 1713 xmlOutputBufferWriteString(buf, (const char *) child->content); 1714 /* (We cannot use xhtmlNodeDumpOutput() here because 1715 * we wish to leave '>' unescaped!) */ 1716 ctxt->level = level; 1717 ctxt->format = indent; 1718 } else { 1719 /* We must use a CDATA section. Unfortunately, 1720 * this will break CSS and JavaScript when read by 1721 * a browser in HTML4-compliant mode. :-( */ 1722 start = end = child->content; 1723 while (*end != '\0') { 1724 if (*end == ']' && 1725 *(end + 1) == ']' && 1726 *(end + 2) == '>') { 1727 end = end + 2; 1728 xmlOutputBufferWrite(buf, 9, "<![CDATA["); 1729 xmlOutputBufferWrite(buf, end - start, 1730 (const char *)start); 1731 xmlOutputBufferWrite(buf, 3, "]]>"); 1732 start = end; 1733 } 1734 end++; 1735 } 1736 if (start != end) { 1737 xmlOutputBufferWrite(buf, 9, "<![CDATA["); 1738 xmlOutputBufferWrite(buf, end - start, 1739 (const char *)start); 1740 xmlOutputBufferWrite(buf, 3, "]]>"); 1741 } 1742 } 1743 } else { 1744 int level = ctxt->level; 1745 int indent = ctxt->format; 1746 1747 ctxt->level = 0; 1748 ctxt->format = 0; 1749 xhtmlNodeDumpOutput(ctxt, child); 1750 ctxt->level = level; 1751 ctxt->format = indent; 1752 } 1753 child = child->next; 1754 } 1755 } 1756 #endif 1757 1758 if (cur->children != NULL) { 1759 int indent = ctxt->format; 1760 1761 if (format == 1) xmlOutputBufferWrite(buf, 1, "\n"); 1762 if (ctxt->level >= 0) ctxt->level++; 1763 ctxt->format = format; 1764 xhtmlNodeListDumpOutput(ctxt, cur->children); 1765 if (ctxt->level > 0) ctxt->level--; 1766 ctxt->format = indent; 1767 if ((xmlIndentTreeOutput) && (format == 1)) 1768 xmlOutputBufferWrite(buf, ctxt->indent_size * 1769 (ctxt->level > ctxt->indent_nr ? 1770 ctxt->indent_nr : ctxt->level), 1771 ctxt->indent); 1772 } 1773 xmlOutputBufferWrite(buf, 2, "</"); 1774 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { 1775 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); 1776 xmlOutputBufferWrite(buf, 1, ":"); 1777 } 1778 1779 xmlOutputBufferWriteString(buf, (const char *)cur->name); 1780 xmlOutputBufferWrite(buf, 1, ">"); 1781 } 1782 #endif 1783 1784 /************************************************************************ 1785 * * 1786 * Public entry points * 1787 * * 1788 ************************************************************************/ 1789 1790 /** 1791 * xmlSaveToFd: 1792 * @fd: a file descriptor number 1793 * @encoding: the encoding name to use or NULL 1794 * @options: a set of xmlSaveOptions 1795 * 1796 * Create a document saving context serializing to a file descriptor 1797 * with the encoding and the options given. 1798 * 1799 * Returns a new serialization context or NULL in case of error. 1800 */ 1801 xmlSaveCtxtPtr 1802 xmlSaveToFd(int fd, const char *encoding, int options) 1803 { 1804 xmlSaveCtxtPtr ret; 1805 1806 ret = xmlNewSaveCtxt(encoding, options); 1807 if (ret == NULL) return(NULL); 1808 ret->buf = xmlOutputBufferCreateFd(fd, ret->handler); 1809 if (ret->buf == NULL) { 1810 xmlFreeSaveCtxt(ret); 1811 return(NULL); 1812 } 1813 return(ret); 1814 } 1815 1816 /** 1817 * xmlSaveToFilename: 1818 * @filename: a file name or an URL 1819 * @encoding: the encoding name to use or NULL 1820 * @options: a set of xmlSaveOptions 1821 * 1822 * Create a document saving context serializing to a filename or possibly 1823 * to an URL (but this is less reliable) with the encoding and the options 1824 * given. 1825 * 1826 * Returns a new serialization context or NULL in case of error. 1827 */ 1828 xmlSaveCtxtPtr 1829 xmlSaveToFilename(const char *filename, const char *encoding, int options) 1830 { 1831 xmlSaveCtxtPtr ret; 1832 int compression = 0; /* TODO handle compression option */ 1833 1834 ret = xmlNewSaveCtxt(encoding, options); 1835 if (ret == NULL) return(NULL); 1836 ret->buf = xmlOutputBufferCreateFilename(filename, ret->handler, 1837 compression); 1838 if (ret->buf == NULL) { 1839 xmlFreeSaveCtxt(ret); 1840 return(NULL); 1841 } 1842 return(ret); 1843 } 1844 1845 /** 1846 * xmlSaveToBuffer: 1847 * @buffer: a buffer 1848 * @encoding: the encoding name to use or NULL 1849 * @options: a set of xmlSaveOptions 1850 * 1851 * Create a document saving context serializing to a buffer 1852 * with the encoding and the options given 1853 * 1854 * Returns a new serialization context or NULL in case of error. 1855 */ 1856 1857 xmlSaveCtxtPtr 1858 xmlSaveToBuffer(xmlBufferPtr buffer, const char *encoding, int options) 1859 { 1860 xmlSaveCtxtPtr ret; 1861 xmlOutputBufferPtr out_buff; 1862 xmlCharEncodingHandlerPtr handler; 1863 1864 ret = xmlNewSaveCtxt(encoding, options); 1865 if (ret == NULL) return(NULL); 1866 1867 if (encoding != NULL) { 1868 handler = xmlFindCharEncodingHandler(encoding); 1869 if (handler == NULL) { 1870 xmlFree(ret); 1871 return(NULL); 1872 } 1873 } else 1874 handler = NULL; 1875 out_buff = xmlOutputBufferCreateBuffer(buffer, handler); 1876 if (out_buff == NULL) { 1877 xmlFree(ret); 1878 if (handler) xmlCharEncCloseFunc(handler); 1879 return(NULL); 1880 } 1881 1882 ret->buf = out_buff; 1883 return(ret); 1884 } 1885 1886 /** 1887 * xmlSaveToIO: 1888 * @iowrite: an I/O write function 1889 * @ioclose: an I/O close function 1890 * @ioctx: an I/O handler 1891 * @encoding: the encoding name to use or NULL 1892 * @options: a set of xmlSaveOptions 1893 * 1894 * Create a document saving context serializing to a file descriptor 1895 * with the encoding and the options given 1896 * 1897 * Returns a new serialization context or NULL in case of error. 1898 */ 1899 xmlSaveCtxtPtr 1900 xmlSaveToIO(xmlOutputWriteCallback iowrite, 1901 xmlOutputCloseCallback ioclose, 1902 void *ioctx, const char *encoding, int options) 1903 { 1904 xmlSaveCtxtPtr ret; 1905 1906 ret = xmlNewSaveCtxt(encoding, options); 1907 if (ret == NULL) return(NULL); 1908 ret->buf = xmlOutputBufferCreateIO(iowrite, ioclose, ioctx, ret->handler); 1909 if (ret->buf == NULL) { 1910 xmlFreeSaveCtxt(ret); 1911 return(NULL); 1912 } 1913 return(ret); 1914 } 1915 1916 /** 1917 * xmlSaveDoc: 1918 * @ctxt: a document saving context 1919 * @doc: a document 1920 * 1921 * Save a full document to a saving context 1922 * TODO: The function is not fully implemented yet as it does not return the 1923 * byte count but 0 instead 1924 * 1925 * Returns the number of byte written or -1 in case of error 1926 */ 1927 long 1928 xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc) 1929 { 1930 long ret = 0; 1931 1932 if ((ctxt == NULL) || (doc == NULL)) return(-1); 1933 if (xmlDocContentDumpOutput(ctxt, doc) < 0) 1934 return(-1); 1935 return(ret); 1936 } 1937 1938 /** 1939 * xmlSaveTree: 1940 * @ctxt: a document saving context 1941 * @node: the top node of the subtree to save 1942 * 1943 * Save a subtree starting at the node parameter to a saving context 1944 * TODO: The function is not fully implemented yet as it does not return the 1945 * byte count but 0 instead 1946 * 1947 * Returns the number of byte written or -1 in case of error 1948 */ 1949 long 1950 xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr node) 1951 { 1952 long ret = 0; 1953 1954 if ((ctxt == NULL) || (node == NULL)) return(-1); 1955 xmlNodeDumpOutputInternal(ctxt, node); 1956 return(ret); 1957 } 1958 1959 /** 1960 * xmlSaveFlush: 1961 * @ctxt: a document saving context 1962 * 1963 * Flush a document saving context, i.e. make sure that all bytes have 1964 * been output. 1965 * 1966 * Returns the number of byte written or -1 in case of error. 1967 */ 1968 int 1969 xmlSaveFlush(xmlSaveCtxtPtr ctxt) 1970 { 1971 if (ctxt == NULL) return(-1); 1972 if (ctxt->buf == NULL) return(-1); 1973 return(xmlOutputBufferFlush(ctxt->buf)); 1974 } 1975 1976 /** 1977 * xmlSaveClose: 1978 * @ctxt: a document saving context 1979 * 1980 * Close a document saving context, i.e. make sure that all bytes have 1981 * been output and free the associated data. 1982 * 1983 * Returns the number of byte written or -1 in case of error. 1984 */ 1985 int 1986 xmlSaveClose(xmlSaveCtxtPtr ctxt) 1987 { 1988 int ret; 1989 1990 if (ctxt == NULL) return(-1); 1991 ret = xmlSaveFlush(ctxt); 1992 xmlFreeSaveCtxt(ctxt); 1993 return(ret); 1994 } 1995 1996 /** 1997 * xmlSaveSetEscape: 1998 * @ctxt: a document saving context 1999 * @escape: the escaping function 2000 * 2001 * Set a custom escaping function to be used for text in element content 2002 * 2003 * Returns 0 if successful or -1 in case of error. 2004 */ 2005 int 2006 xmlSaveSetEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape) 2007 { 2008 if (ctxt == NULL) return(-1); 2009 ctxt->escape = escape; 2010 return(0); 2011 } 2012 2013 /** 2014 * xmlSaveSetAttrEscape: 2015 * @ctxt: a document saving context 2016 * @escape: the escaping function 2017 * 2018 * Set a custom escaping function to be used for text in attribute content 2019 * 2020 * Returns 0 if successful or -1 in case of error. 2021 */ 2022 int 2023 xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape) 2024 { 2025 if (ctxt == NULL) return(-1); 2026 ctxt->escapeAttr = escape; 2027 return(0); 2028 } 2029 2030 /************************************************************************ 2031 * * 2032 * Public entry points based on buffers * 2033 * * 2034 ************************************************************************/ 2035 2036 /** 2037 * xmlBufAttrSerializeTxtContent: 2038 * @buf: and xmlBufPtr output 2039 * @doc: the document 2040 * @attr: the attribute node 2041 * @string: the text content 2042 * 2043 * Serialize text attribute values to an xmlBufPtr 2044 */ 2045 void 2046 xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc, 2047 xmlAttrPtr attr, const xmlChar * string) 2048 { 2049 xmlChar *base, *cur; 2050 2051 if (string == NULL) 2052 return; 2053 base = cur = (xmlChar *) string; 2054 while (*cur != 0) { 2055 if (*cur == '\n') { 2056 if (base != cur) 2057 xmlBufAdd(buf, base, cur - base); 2058 xmlBufAdd(buf, BAD_CAST " ", 5); 2059 cur++; 2060 base = cur; 2061 } else if (*cur == '\r') { 2062 if (base != cur) 2063 xmlBufAdd(buf, base, cur - base); 2064 xmlBufAdd(buf, BAD_CAST " ", 5); 2065 cur++; 2066 base = cur; 2067 } else if (*cur == '\t') { 2068 if (base != cur) 2069 xmlBufAdd(buf, base, cur - base); 2070 xmlBufAdd(buf, BAD_CAST "	", 4); 2071 cur++; 2072 base = cur; 2073 } else if (*cur == '"') { 2074 if (base != cur) 2075 xmlBufAdd(buf, base, cur - base); 2076 xmlBufAdd(buf, BAD_CAST """, 6); 2077 cur++; 2078 base = cur; 2079 } else if (*cur == '<') { 2080 if (base != cur) 2081 xmlBufAdd(buf, base, cur - base); 2082 xmlBufAdd(buf, BAD_CAST "<", 4); 2083 cur++; 2084 base = cur; 2085 } else if (*cur == '>') { 2086 if (base != cur) 2087 xmlBufAdd(buf, base, cur - base); 2088 xmlBufAdd(buf, BAD_CAST ">", 4); 2089 cur++; 2090 base = cur; 2091 } else if (*cur == '&') { 2092 if (base != cur) 2093 xmlBufAdd(buf, base, cur - base); 2094 xmlBufAdd(buf, BAD_CAST "&", 5); 2095 cur++; 2096 base = cur; 2097 } else if ((*cur >= 0x80) && (cur[1] != 0) && 2098 ((doc == NULL) || (doc->encoding == NULL))) { 2099 /* 2100 * We assume we have UTF-8 content. 2101 */ 2102 unsigned char tmp[12]; 2103 int val = 0, l = 1; 2104 2105 if (base != cur) 2106 xmlBufAdd(buf, base, cur - base); 2107 if (*cur < 0xC0) { 2108 xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL); 2109 xmlSerializeHexCharRef(tmp, *cur); 2110 xmlBufAdd(buf, (xmlChar *) tmp, -1); 2111 cur++; 2112 base = cur; 2113 continue; 2114 } else if (*cur < 0xE0) { 2115 val = (cur[0]) & 0x1F; 2116 val <<= 6; 2117 val |= (cur[1]) & 0x3F; 2118 l = 2; 2119 } else if ((*cur < 0xF0) && (cur [2] != 0)) { 2120 val = (cur[0]) & 0x0F; 2121 val <<= 6; 2122 val |= (cur[1]) & 0x3F; 2123 val <<= 6; 2124 val |= (cur[2]) & 0x3F; 2125 l = 3; 2126 } else if ((*cur < 0xF8) && (cur [2] != 0) && (cur[3] != 0)) { 2127 val = (cur[0]) & 0x07; 2128 val <<= 6; 2129 val |= (cur[1]) & 0x3F; 2130 val <<= 6; 2131 val |= (cur[2]) & 0x3F; 2132 val <<= 6; 2133 val |= (cur[3]) & 0x3F; 2134 l = 4; 2135 } 2136 if ((l == 1) || (!IS_CHAR(val))) { 2137 xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL); 2138 xmlSerializeHexCharRef(tmp, *cur); 2139 xmlBufAdd(buf, (xmlChar *) tmp, -1); 2140 cur++; 2141 base = cur; 2142 continue; 2143 } 2144 /* 2145 * We could do multiple things here. Just save 2146 * as a char ref 2147 */ 2148 xmlSerializeHexCharRef(tmp, val); 2149 xmlBufAdd(buf, (xmlChar *) tmp, -1); 2150 cur += l; 2151 base = cur; 2152 } else { 2153 cur++; 2154 } 2155 } 2156 if (base != cur) 2157 xmlBufAdd(buf, base, cur - base); 2158 } 2159 2160 /** 2161 * xmlAttrSerializeTxtContent: 2162 * @buf: the XML buffer output 2163 * @doc: the document 2164 * @attr: the attribute node 2165 * @string: the text content 2166 * 2167 * Serialize text attribute values to an xml simple buffer 2168 */ 2169 void 2170 xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc, 2171 xmlAttrPtr attr, const xmlChar * string) 2172 { 2173 xmlBufPtr buffer; 2174 2175 if ((buf == NULL) || (string == NULL)) 2176 return; 2177 buffer = xmlBufFromBuffer(buf); 2178 if (buffer == NULL) 2179 return; 2180 xmlBufAttrSerializeTxtContent(buffer, doc, attr, string); 2181 xmlBufBackToBuffer(buffer); 2182 } 2183 2184 /** 2185 * xmlNodeDump: 2186 * @buf: the XML buffer output 2187 * @doc: the document 2188 * @cur: the current node 2189 * @level: the imbrication level for indenting 2190 * @format: is formatting allowed 2191 * 2192 * Dump an XML node, recursive behaviour,children are printed too. 2193 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 2194 * or xmlKeepBlanksDefault(0) was called 2195 * Since this is using xmlBuffer structures it is limited to 2GB and somehow 2196 * deprecated, use xmlBufNodeDump() instead. 2197 * 2198 * Returns the number of bytes written to the buffer or -1 in case of error 2199 */ 2200 int 2201 xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, 2202 int format) 2203 { 2204 xmlBufPtr buffer; 2205 int ret; 2206 2207 if ((buf == NULL) || (cur == NULL)) 2208 return(-1); 2209 buffer = xmlBufFromBuffer(buf); 2210 if (buffer == NULL) 2211 return(-1); 2212 ret = xmlBufNodeDump(buffer, doc, cur, level, format); 2213 xmlBufBackToBuffer(buffer); 2214 if (ret > INT_MAX) 2215 return(-1); 2216 return((int) ret); 2217 } 2218 2219 /** 2220 * xmlBufNodeDump: 2221 * @buf: the XML buffer output 2222 * @doc: the document 2223 * @cur: the current node 2224 * @level: the imbrication level for indenting 2225 * @format: is formatting allowed 2226 * 2227 * Dump an XML node, recursive behaviour,children are printed too. 2228 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 2229 * or xmlKeepBlanksDefault(0) was called 2230 * 2231 * Returns the number of bytes written to the buffer, in case of error 0 2232 * is returned or @buf stores the error 2233 */ 2234 2235 size_t 2236 xmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, 2237 int format) 2238 { 2239 size_t use; 2240 int ret; 2241 xmlOutputBufferPtr outbuf; 2242 int oldalloc; 2243 2244 xmlInitParser(); 2245 2246 if (cur == NULL) { 2247 #ifdef DEBUG_TREE 2248 xmlGenericError(xmlGenericErrorContext, 2249 "xmlNodeDump : node == NULL\n"); 2250 #endif 2251 return (-1); 2252 } 2253 if (buf == NULL) { 2254 #ifdef DEBUG_TREE 2255 xmlGenericError(xmlGenericErrorContext, 2256 "xmlNodeDump : buf == NULL\n"); 2257 #endif 2258 return (-1); 2259 } 2260 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); 2261 if (outbuf == NULL) { 2262 xmlSaveErrMemory("creating buffer"); 2263 return (-1); 2264 } 2265 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer)); 2266 outbuf->buffer = buf; 2267 outbuf->encoder = NULL; 2268 outbuf->writecallback = NULL; 2269 outbuf->closecallback = NULL; 2270 outbuf->context = NULL; 2271 outbuf->written = 0; 2272 2273 use = xmlBufUse(buf); 2274 oldalloc = xmlBufGetAllocationScheme(buf); 2275 xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); 2276 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL); 2277 xmlBufSetAllocationScheme(buf, oldalloc); 2278 xmlFree(outbuf); 2279 ret = xmlBufUse(buf) - use; 2280 return (ret); 2281 } 2282 2283 /** 2284 * xmlElemDump: 2285 * @f: the FILE * for the output 2286 * @doc: the document 2287 * @cur: the current node 2288 * 2289 * Dump an XML/HTML node, recursive behaviour, children are printed too. 2290 */ 2291 void 2292 xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur) 2293 { 2294 xmlOutputBufferPtr outbuf; 2295 2296 xmlInitParser(); 2297 2298 if (cur == NULL) { 2299 #ifdef DEBUG_TREE 2300 xmlGenericError(xmlGenericErrorContext, 2301 "xmlElemDump : cur == NULL\n"); 2302 #endif 2303 return; 2304 } 2305 #ifdef DEBUG_TREE 2306 if (doc == NULL) { 2307 xmlGenericError(xmlGenericErrorContext, 2308 "xmlElemDump : doc == NULL\n"); 2309 } 2310 #endif 2311 2312 outbuf = xmlOutputBufferCreateFile(f, NULL); 2313 if (outbuf == NULL) 2314 return; 2315 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { 2316 #ifdef LIBXML_HTML_ENABLED 2317 htmlNodeDumpOutput(outbuf, doc, cur, NULL); 2318 #else 2319 xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n"); 2320 #endif /* LIBXML_HTML_ENABLED */ 2321 } else 2322 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL); 2323 xmlOutputBufferClose(outbuf); 2324 } 2325 2326 /************************************************************************ 2327 * * 2328 * Saving functions front-ends * 2329 * * 2330 ************************************************************************/ 2331 2332 /** 2333 * xmlNodeDumpOutput: 2334 * @buf: the XML buffer output 2335 * @doc: the document 2336 * @cur: the current node 2337 * @level: the imbrication level for indenting 2338 * @format: is formatting allowed 2339 * @encoding: an optional encoding string 2340 * 2341 * Dump an XML node, recursive behaviour, children are printed too. 2342 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 2343 * or xmlKeepBlanksDefault(0) was called 2344 */ 2345 void 2346 xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, 2347 int level, int format, const char *encoding) 2348 { 2349 xmlSaveCtxt ctxt; 2350 #ifdef LIBXML_HTML_ENABLED 2351 xmlDtdPtr dtd; 2352 int is_xhtml = 0; 2353 #endif 2354 2355 xmlInitParser(); 2356 2357 if ((buf == NULL) || (cur == NULL)) return; 2358 2359 if (encoding == NULL) 2360 encoding = "UTF-8"; 2361 2362 memset(&ctxt, 0, sizeof(ctxt)); 2363 ctxt.doc = doc; 2364 ctxt.buf = buf; 2365 ctxt.level = level; 2366 ctxt.format = format ? 1 : 0; 2367 ctxt.encoding = (const xmlChar *) encoding; 2368 xmlSaveCtxtInit(&ctxt); 2369 ctxt.options |= XML_SAVE_AS_XML; 2370 2371 #ifdef LIBXML_HTML_ENABLED 2372 dtd = xmlGetIntSubset(doc); 2373 if (dtd != NULL) { 2374 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID); 2375 if (is_xhtml < 0) 2376 is_xhtml = 0; 2377 } 2378 2379 if (is_xhtml) 2380 xhtmlNodeDumpOutput(&ctxt, cur); 2381 else 2382 #endif 2383 xmlNodeDumpOutputInternal(&ctxt, cur); 2384 } 2385 2386 /** 2387 * xmlDocDumpFormatMemoryEnc: 2388 * @out_doc: Document to generate XML text from 2389 * @doc_txt_ptr: Memory pointer for allocated XML text 2390 * @doc_txt_len: Length of the generated XML text 2391 * @txt_encoding: Character encoding to use when generating XML text 2392 * @format: should formatting spaces been added 2393 * 2394 * Dump the current DOM tree into memory using the character encoding specified 2395 * by the caller. Note it is up to the caller of this function to free the 2396 * allocated memory with xmlFree(). 2397 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 2398 * or xmlKeepBlanksDefault(0) was called 2399 */ 2400 2401 void 2402 xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, 2403 int * doc_txt_len, const char * txt_encoding, 2404 int format) { 2405 xmlSaveCtxt ctxt; 2406 int dummy = 0; 2407 xmlOutputBufferPtr out_buff = NULL; 2408 xmlCharEncodingHandlerPtr conv_hdlr = NULL; 2409 2410 if (doc_txt_len == NULL) { 2411 doc_txt_len = &dummy; /* Continue, caller just won't get length */ 2412 } 2413 2414 if (doc_txt_ptr == NULL) { 2415 *doc_txt_len = 0; 2416 return; 2417 } 2418 2419 *doc_txt_ptr = NULL; 2420 *doc_txt_len = 0; 2421 2422 if (out_doc == NULL) { 2423 /* No document, no output */ 2424 return; 2425 } 2426 2427 /* 2428 * Validate the encoding value, if provided. 2429 * This logic is copied from xmlSaveFileEnc. 2430 */ 2431 2432 if (txt_encoding == NULL) 2433 txt_encoding = (const char *) out_doc->encoding; 2434 if (txt_encoding != NULL) { 2435 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding); 2436 if ( conv_hdlr == NULL ) { 2437 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc, 2438 txt_encoding); 2439 return; 2440 } 2441 } 2442 2443 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) { 2444 xmlSaveErrMemory("creating buffer"); 2445 return; 2446 } 2447 2448 memset(&ctxt, 0, sizeof(ctxt)); 2449 ctxt.doc = out_doc; 2450 ctxt.buf = out_buff; 2451 ctxt.level = 0; 2452 ctxt.format = format ? 1 : 0; 2453 ctxt.encoding = (const xmlChar *) txt_encoding; 2454 xmlSaveCtxtInit(&ctxt); 2455 ctxt.options |= XML_SAVE_AS_XML; 2456 xmlDocContentDumpOutput(&ctxt, out_doc); 2457 xmlOutputBufferFlush(out_buff); 2458 if (out_buff->conv != NULL) { 2459 *doc_txt_len = xmlBufUse(out_buff->conv); 2460 *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->conv), *doc_txt_len); 2461 } else { 2462 *doc_txt_len = xmlBufUse(out_buff->buffer); 2463 *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->buffer),*doc_txt_len); 2464 } 2465 (void)xmlOutputBufferClose(out_buff); 2466 2467 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) { 2468 *doc_txt_len = 0; 2469 xmlSaveErrMemory("creating output"); 2470 } 2471 2472 return; 2473 } 2474 2475 /** 2476 * xmlDocDumpMemory: 2477 * @cur: the document 2478 * @mem: OUT: the memory pointer 2479 * @size: OUT: the memory length 2480 * 2481 * Dump an XML document in memory and return the #xmlChar * and it's size 2482 * in bytes. It's up to the caller to free the memory with xmlFree(). 2483 * The resulting byte array is zero terminated, though the last 0 is not 2484 * included in the returned size. 2485 */ 2486 void 2487 xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) { 2488 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0); 2489 } 2490 2491 /** 2492 * xmlDocDumpFormatMemory: 2493 * @cur: the document 2494 * @mem: OUT: the memory pointer 2495 * @size: OUT: the memory length 2496 * @format: should formatting spaces been added 2497 * 2498 * 2499 * Dump an XML document in memory and return the #xmlChar * and it's size. 2500 * It's up to the caller to free the memory with xmlFree(). 2501 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 2502 * or xmlKeepBlanksDefault(0) was called 2503 */ 2504 void 2505 xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) { 2506 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format); 2507 } 2508 2509 /** 2510 * xmlDocDumpMemoryEnc: 2511 * @out_doc: Document to generate XML text from 2512 * @doc_txt_ptr: Memory pointer for allocated XML text 2513 * @doc_txt_len: Length of the generated XML text 2514 * @txt_encoding: Character encoding to use when generating XML text 2515 * 2516 * Dump the current DOM tree into memory using the character encoding specified 2517 * by the caller. Note it is up to the caller of this function to free the 2518 * allocated memory with xmlFree(). 2519 */ 2520 2521 void 2522 xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, 2523 int * doc_txt_len, const char * txt_encoding) { 2524 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len, 2525 txt_encoding, 0); 2526 } 2527 2528 /** 2529 * xmlDocFormatDump: 2530 * @f: the FILE* 2531 * @cur: the document 2532 * @format: should formatting spaces been added 2533 * 2534 * Dump an XML document to an open FILE. 2535 * 2536 * returns: the number of bytes written or -1 in case of failure. 2537 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 2538 * or xmlKeepBlanksDefault(0) was called 2539 */ 2540 int 2541 xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) { 2542 xmlSaveCtxt ctxt; 2543 xmlOutputBufferPtr buf; 2544 const char * encoding; 2545 xmlCharEncodingHandlerPtr handler = NULL; 2546 int ret; 2547 2548 if (cur == NULL) { 2549 #ifdef DEBUG_TREE 2550 xmlGenericError(xmlGenericErrorContext, 2551 "xmlDocDump : document == NULL\n"); 2552 #endif 2553 return(-1); 2554 } 2555 encoding = (const char *) cur->encoding; 2556 2557 if (encoding != NULL) { 2558 handler = xmlFindCharEncodingHandler(encoding); 2559 if (handler == NULL) { 2560 xmlFree((char *) cur->encoding); 2561 cur->encoding = NULL; 2562 encoding = NULL; 2563 } 2564 } 2565 buf = xmlOutputBufferCreateFile(f, handler); 2566 if (buf == NULL) return(-1); 2567 memset(&ctxt, 0, sizeof(ctxt)); 2568 ctxt.doc = cur; 2569 ctxt.buf = buf; 2570 ctxt.level = 0; 2571 ctxt.format = format ? 1 : 0; 2572 ctxt.encoding = (const xmlChar *) encoding; 2573 xmlSaveCtxtInit(&ctxt); 2574 ctxt.options |= XML_SAVE_AS_XML; 2575 xmlDocContentDumpOutput(&ctxt, cur); 2576 2577 ret = xmlOutputBufferClose(buf); 2578 return(ret); 2579 } 2580 2581 /** 2582 * xmlDocDump: 2583 * @f: the FILE* 2584 * @cur: the document 2585 * 2586 * Dump an XML document to an open FILE. 2587 * 2588 * returns: the number of bytes written or -1 in case of failure. 2589 */ 2590 int 2591 xmlDocDump(FILE *f, xmlDocPtr cur) { 2592 return(xmlDocFormatDump (f, cur, 0)); 2593 } 2594 2595 /** 2596 * xmlSaveFileTo: 2597 * @buf: an output I/O buffer 2598 * @cur: the document 2599 * @encoding: the encoding if any assuming the I/O layer handles the trancoding 2600 * 2601 * Dump an XML document to an I/O buffer. 2602 * Warning ! This call xmlOutputBufferClose() on buf which is not available 2603 * after this call. 2604 * 2605 * returns: the number of bytes written or -1 in case of failure. 2606 */ 2607 int 2608 xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) { 2609 xmlSaveCtxt ctxt; 2610 int ret; 2611 2612 if (buf == NULL) return(-1); 2613 if (cur == NULL) { 2614 xmlOutputBufferClose(buf); 2615 return(-1); 2616 } 2617 memset(&ctxt, 0, sizeof(ctxt)); 2618 ctxt.doc = cur; 2619 ctxt.buf = buf; 2620 ctxt.level = 0; 2621 ctxt.format = 0; 2622 ctxt.encoding = (const xmlChar *) encoding; 2623 xmlSaveCtxtInit(&ctxt); 2624 ctxt.options |= XML_SAVE_AS_XML; 2625 xmlDocContentDumpOutput(&ctxt, cur); 2626 ret = xmlOutputBufferClose(buf); 2627 return(ret); 2628 } 2629 2630 /** 2631 * xmlSaveFormatFileTo: 2632 * @buf: an output I/O buffer 2633 * @cur: the document 2634 * @encoding: the encoding if any assuming the I/O layer handles the trancoding 2635 * @format: should formatting spaces been added 2636 * 2637 * Dump an XML document to an I/O buffer. 2638 * Warning ! This call xmlOutputBufferClose() on buf which is not available 2639 * after this call. 2640 * 2641 * returns: the number of bytes written or -1 in case of failure. 2642 */ 2643 int 2644 xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, 2645 const char *encoding, int format) 2646 { 2647 xmlSaveCtxt ctxt; 2648 int ret; 2649 2650 if (buf == NULL) return(-1); 2651 if ((cur == NULL) || 2652 ((cur->type != XML_DOCUMENT_NODE) && 2653 (cur->type != XML_HTML_DOCUMENT_NODE))) { 2654 xmlOutputBufferClose(buf); 2655 return(-1); 2656 } 2657 memset(&ctxt, 0, sizeof(ctxt)); 2658 ctxt.doc = cur; 2659 ctxt.buf = buf; 2660 ctxt.level = 0; 2661 ctxt.format = format ? 1 : 0; 2662 ctxt.encoding = (const xmlChar *) encoding; 2663 xmlSaveCtxtInit(&ctxt); 2664 ctxt.options |= XML_SAVE_AS_XML; 2665 xmlDocContentDumpOutput(&ctxt, cur); 2666 ret = xmlOutputBufferClose(buf); 2667 return (ret); 2668 } 2669 2670 /** 2671 * xmlSaveFormatFileEnc: 2672 * @filename: the filename or URL to output 2673 * @cur: the document being saved 2674 * @encoding: the name of the encoding to use or NULL. 2675 * @format: should formatting spaces be added. 2676 * 2677 * Dump an XML document to a file or an URL. 2678 * 2679 * Returns the number of bytes written or -1 in case of error. 2680 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 2681 * or xmlKeepBlanksDefault(0) was called 2682 */ 2683 int 2684 xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur, 2685 const char * encoding, int format ) { 2686 xmlSaveCtxt ctxt; 2687 xmlOutputBufferPtr buf; 2688 xmlCharEncodingHandlerPtr handler = NULL; 2689 int ret; 2690 2691 if (cur == NULL) 2692 return(-1); 2693 2694 if (encoding == NULL) 2695 encoding = (const char *) cur->encoding; 2696 2697 if (encoding != NULL) { 2698 2699 handler = xmlFindCharEncodingHandler(encoding); 2700 if (handler == NULL) 2701 return(-1); 2702 } 2703 2704 #ifdef LIBXML_ZLIB_ENABLED 2705 if (cur->compression < 0) cur->compression = xmlGetCompressMode(); 2706 #endif 2707 /* 2708 * save the content to a temp buffer. 2709 */ 2710 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression); 2711 if (buf == NULL) return(-1); 2712 memset(&ctxt, 0, sizeof(ctxt)); 2713 ctxt.doc = cur; 2714 ctxt.buf = buf; 2715 ctxt.level = 0; 2716 ctxt.format = format ? 1 : 0; 2717 ctxt.encoding = (const xmlChar *) encoding; 2718 xmlSaveCtxtInit(&ctxt); 2719 ctxt.options |= XML_SAVE_AS_XML; 2720 2721 xmlDocContentDumpOutput(&ctxt, cur); 2722 2723 ret = xmlOutputBufferClose(buf); 2724 return(ret); 2725 } 2726 2727 2728 /** 2729 * xmlSaveFileEnc: 2730 * @filename: the filename (or URL) 2731 * @cur: the document 2732 * @encoding: the name of an encoding (or NULL) 2733 * 2734 * Dump an XML document, converting it to the given encoding 2735 * 2736 * returns: the number of bytes written or -1 in case of failure. 2737 */ 2738 int 2739 xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) { 2740 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) ); 2741 } 2742 2743 /** 2744 * xmlSaveFormatFile: 2745 * @filename: the filename (or URL) 2746 * @cur: the document 2747 * @format: should formatting spaces been added 2748 * 2749 * Dump an XML document to a file. Will use compression if 2750 * compiled in and enabled. If @filename is "-" the stdout file is 2751 * used. If @format is set then the document will be indented on output. 2752 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 2753 * or xmlKeepBlanksDefault(0) was called 2754 * 2755 * returns: the number of bytes written or -1 in case of failure. 2756 */ 2757 int 2758 xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) { 2759 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) ); 2760 } 2761 2762 /** 2763 * xmlSaveFile: 2764 * @filename: the filename (or URL) 2765 * @cur: the document 2766 * 2767 * Dump an XML document to a file. Will use compression if 2768 * compiled in and enabled. If @filename is "-" the stdout file is 2769 * used. 2770 * returns: the number of bytes written or -1 in case of failure. 2771 */ 2772 int 2773 xmlSaveFile(const char *filename, xmlDocPtr cur) { 2774 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0)); 2775 } 2776 2777 #endif /* LIBXML_OUTPUT_ENABLED */ 2778 2779 #define bottom_xmlsave 2780 #include "elfgcchack.h" 2781