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