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