diff options
Diffstat (limited to 'xmlsave.c')
-rw-r--r-- | xmlsave.c | 654 |
1 files changed, 418 insertions, 236 deletions
@@ -14,11 +14,11 @@ #include <libxml/parserInternals.h> #include <libxml/tree.h> #include <libxml/xmlsave.h> -#ifdef LIBXML_HTML_ENABLED -#include <libxml/HTMLtree.h> #define MAX_INDENT 60 +#include <libxml/HTMLtree.h> + /************************************************************************ * * * XHTML detection * @@ -63,8 +63,6 @@ xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) { } return(0); } -#endif /* LIBXML_HTML_ENABLED */ - #ifdef LIBXML_OUTPUT_ENABLED @@ -85,9 +83,11 @@ struct _xmlSaveCtxt { int options; int level; int format; - char indent[MAX_INDENT + 1]; + char indent[MAX_INDENT + 1]; /* array for indenting output */ int indent_nr; int indent_size; + xmlCharEncodingOutputFunc escape; /* used for element content */ + xmlCharEncodingOutputFunc escapeAttr;/* used for attribute content */ }; /************************************************************************ @@ -141,6 +141,179 @@ xmlSaveErr(int code, xmlNodePtr node, const char *extra) /************************************************************************ * * + * Special escaping routines * + * * + ************************************************************************/ +static unsigned char * +xmlSerializeHexCharRef(unsigned char *out, int val) { + unsigned char *ptr; + + *out++ = '&'; + *out++ = '#'; + *out++ = 'x'; + if (val < 0x10) ptr = out; + else if (val < 0x100) ptr = out + 1; + else if (val < 0x1000) ptr = out + 2; + else if (val < 0x10000) ptr = out + 3; + else if (val < 0x100000) ptr = out + 4; + else ptr = out + 5; + out = ptr + 1; + while (val > 0) { + switch (val & 0xF) { + case 0: *ptr-- = '0'; break; + case 1: *ptr-- = '1'; break; + case 2: *ptr-- = '2'; break; + case 3: *ptr-- = '3'; break; + case 4: *ptr-- = '4'; break; + case 5: *ptr-- = '5'; break; + case 6: *ptr-- = '6'; break; + case 7: *ptr-- = '7'; break; + case 8: *ptr-- = '8'; break; + case 9: *ptr-- = '9'; break; + case 0xA: *ptr-- = 'A'; break; + case 0xB: *ptr-- = 'B'; break; + case 0xC: *ptr-- = 'C'; break; + case 0xD: *ptr-- = 'D'; break; + case 0xE: *ptr-- = 'E'; break; + case 0xF: *ptr-- = 'F'; break; + default: *ptr-- = '0'; break; + } + val >>= 4; + } + *out++ = ';'; + *out = 0; + return(out); +} + +/** + * xmlEscapeEntities: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of unescaped UTF-8 bytes + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and escape them. Used when there is no + * encoding specified. + * + * Returns 0 if success, or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + * The value of @outlen after return is the number of octets consumed. + */ +static int +xmlEscapeEntities(unsigned char* out, int *outlen, + const xmlChar* in, int *inlen) { + unsigned char* outstart = out; + const unsigned char* base = in; + unsigned char* outend = out + *outlen; + const unsigned char* inend; + int val; + + inend = in + (*inlen); + + while ((in < inend) && (out < outend)) { + if (*in == '<') { + if (outend - out < 4) break; + *out++ = '&'; + *out++ = 'l'; + *out++ = 't'; + *out++ = ';'; + in++; + continue; + } else if (*in == '>') { + if (outend - out < 4) break; + *out++ = '&'; + *out++ = 'g'; + *out++ = 't'; + *out++ = ';'; + in++; + continue; + } else if (*in == '&') { + if (outend - out < 5) break; + *out++ = '&'; + *out++ = 'a'; + *out++ = 'm'; + *out++ = 'p'; + *out++ = ';'; + in++; + continue; + } else if (((*in >= 0x20) && (*in < 0x80)) || + (*in == '\n') || (*in == '\t')) { + /* + * default case, just copy ! + */ + *out++ = *in++; + continue; + } else if (*in >= 0x80) { + /* + * We assume we have UTF-8 input. + */ + if (outend - out < 10) break; + + if (*in < 0xC0) { + xmlSaveErr(XML_SAVE_NOT_UTF8, NULL, NULL); + in++; + goto error; + } else if (*in < 0xE0) { + if (inend - in < 2) break; + val = (in[0]) & 0x1F; + val <<= 6; + val |= (in[1]) & 0x3F; + in += 2; + } else if (*in < 0xF0) { + if (inend - in < 3) break; + val = (in[0]) & 0x0F; + val <<= 6; + val |= (in[1]) & 0x3F; + val <<= 6; + val |= (in[2]) & 0x3F; + in += 3; + } else if (*in < 0xF8) { + if (inend - in < 4) break; + val = (in[0]) & 0x07; + val <<= 6; + val |= (in[1]) & 0x3F; + val <<= 6; + val |= (in[2]) & 0x3F; + val <<= 6; + val |= (in[3]) & 0x3F; + in += 4; + } else { + xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL); + in++; + goto error; + } + if (!IS_CHAR(val)) { + xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL); + in++; + goto error; + } + + /* + * We could do multiple things here. Just save as a char ref + */ + out = xmlSerializeHexCharRef(out, val); + } else if (IS_BYTE_CHAR(*in)) { + if (outend - out < 6) break; + out = xmlSerializeHexCharRef(out, *in++); + } else { + xmlGenericError(xmlGenericErrorContext, + "xmlEscapeEntities : char out of range\n"); + in++; + goto error; + } + } + *outlen = out - outstart; + *inlen = in - base; + return(0); +error: + *outlen = out - outstart; + *inlen = in - base; + return(-1); +} + +/************************************************************************ + * * * Allocation and deallocation * * * ************************************************************************/ @@ -156,6 +329,8 @@ xmlSaveCtxtInit(xmlSaveCtxtPtr ctxt) int i; if (ctxt == NULL) return; + if ((ctxt->encoding == NULL) && (ctxt->escape == NULL)) + ctxt->escape = xmlEscapeEntities; if (xmlTreeIndentString == NULL) { memset(&ctxt->indent[0], 0, MAX_INDENT + 1); } else { @@ -179,6 +354,8 @@ xmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt) if (ctxt == NULL) return; if (ctxt->encoding != NULL) xmlFree((char *) ctxt->encoding); + if (ctxt->buf != NULL) + xmlOutputBufferClose(ctxt->buf); xmlFree(ctxt); } @@ -209,6 +386,7 @@ xmlNewSaveCtxt(const char *encoding, int options) return(NULL); } ret->encoding = xmlStrdup((const xmlChar *)encoding); + ret->escape = xmlEscapeEntities; } xmlSaveCtxtInit(ret); @@ -229,7 +407,7 @@ xmlNewSaveCtxt(const char *encoding, int options) * Serialize the attribute in the buffer */ static void -xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) +xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr) { xmlNodePtr children; @@ -237,13 +415,14 @@ xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) while (children != NULL) { switch (children->type) { case XML_TEXT_NODE: - xmlAttrSerializeTxtContent(buf, doc, attr, children->content); + xmlAttrSerializeTxtContent(buf->buffer, attr->doc, + attr, children->content); break; case XML_ENTITY_REF_NODE: - xmlBufferAdd(buf, BAD_CAST "&", 1); - xmlBufferAdd(buf, children->name, + xmlBufferAdd(buf->buffer, BAD_CAST "&", 1); + xmlBufferAdd(buf->buffer, children->name, xmlStrlen(children->name)); - xmlBufferAdd(buf, BAD_CAST ";", 1); + xmlBufferAdd(buf->buffer, BAD_CAST ";", 1); break; default: /* should not happen unless we have a badly built tree */ @@ -284,11 +463,11 @@ xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { /* Within the context of an element attributes */ if (cur->prefix != NULL) { - xmlOutputBufferWriteString(buf, " xmlns:"); + xmlOutputBufferWrite(buf, 7, " xmlns:"); xmlOutputBufferWriteString(buf, (const char *)cur->prefix); } else - xmlOutputBufferWriteString(buf, " xmlns"); - xmlOutputBufferWriteString(buf, "="); + xmlOutputBufferWrite(buf, 6, " xmlns"); + xmlOutputBufferWrite(buf, 1, "="); xmlBufferWriteQuotedString(buf->buffer, cur->href); } } @@ -326,24 +505,24 @@ xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) { if ((ctxt == NULL) || (ctxt->buf == NULL)) return; buf = ctxt->buf; - xmlOutputBufferWriteString(buf, "<!DOCTYPE "); + xmlOutputBufferWrite(buf, 10, "<!DOCTYPE "); xmlOutputBufferWriteString(buf, (const char *)dtd->name); if (dtd->ExternalID != NULL) { - xmlOutputBufferWriteString(buf, " PUBLIC "); + xmlOutputBufferWrite(buf, 8, " PUBLIC "); xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID); - xmlOutputBufferWriteString(buf, " "); + xmlOutputBufferWrite(buf, 1, " "); xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID); } else if (dtd->SystemID != NULL) { - xmlOutputBufferWriteString(buf, " SYSTEM "); + xmlOutputBufferWrite(buf, 8, " SYSTEM "); xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID); } if ((dtd->entities == NULL) && (dtd->elements == NULL) && (dtd->attributes == NULL) && (dtd->notations == NULL) && (dtd->pentities == NULL)) { - xmlOutputBufferWriteString(buf, ">"); + xmlOutputBufferWrite(buf, 1, ">"); return; } - xmlOutputBufferWriteString(buf, " [\n"); + xmlOutputBufferWrite(buf, 3, " [\n"); format = ctxt->format; level = ctxt->level; doc = ctxt->doc; @@ -354,7 +533,7 @@ xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) { ctxt->format = format; ctxt->level = level; ctxt->doc = doc; - xmlOutputBufferWriteString(buf, "]>"); + xmlOutputBufferWrite(buf, 2, "]>"); } /** @@ -367,17 +546,18 @@ xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) { static void xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { xmlOutputBufferPtr buf; + if (cur == NULL) return; buf = ctxt->buf; - xmlOutputBufferWriteString(buf, " "); + xmlOutputBufferWrite(buf, 1, " "); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); - xmlOutputBufferWriteString(buf, ":"); + xmlOutputBufferWrite(buf, 1, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, "=\""); - xmlAttrSerializeContent(buf->buffer, ctxt->doc, cur); - xmlOutputBufferWriteString(buf, "\""); + xmlOutputBufferWrite(buf, 2, "=\""); + xmlAttrSerializeContent(buf, cur); + xmlOutputBufferWrite(buf, 1, "\""); } /** @@ -421,7 +601,7 @@ xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { ctxt->indent); xmlNodeDumpOutputInternal(ctxt, cur); if (ctxt->format) { - xmlOutputBufferWriteString(buf, "\n"); + xmlOutputBufferWrite(buf, 1, "\n"); } cur = cur->next; } @@ -470,17 +650,8 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { if (cur->content != NULL) { if ((cur->name == xmlStringText) || (cur->name != xmlStringTextNoenc)) { - xmlChar *buffer; - - if (ctxt->encoding == NULL) - buffer = xmlEncodeEntitiesReentrant(ctxt->doc, - cur->content); - else - buffer = xmlEncodeSpecialChars(ctxt->doc, cur->content); - if (buffer != NULL) { - xmlOutputBufferWriteString(buf, (const char *)buffer); - xmlFree(buffer); - } + + xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape); } else { /* * Disable escaping, needed for XSLT @@ -493,32 +664,32 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { } if (cur->type == XML_PI_NODE) { if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, "<?"); + xmlOutputBufferWrite(buf, 2, "<?"); xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, " "); + xmlOutputBufferWrite(buf, 1, " "); xmlOutputBufferWriteString(buf, (const char *)cur->content); } - xmlOutputBufferWriteString(buf, "?>"); + xmlOutputBufferWrite(buf, 2, "?>"); } else { - xmlOutputBufferWriteString(buf, "<?"); + xmlOutputBufferWrite(buf, 2, "<?"); xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, "?>"); + xmlOutputBufferWrite(buf, 2, "?>"); } return; } if (cur->type == XML_COMMENT_NODE) { if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, "<!--"); + xmlOutputBufferWrite(buf, 4, "<!--"); xmlOutputBufferWriteString(buf, (const char *)cur->content); - xmlOutputBufferWriteString(buf, "-->"); + xmlOutputBufferWrite(buf, 3, "-->"); } return; } if (cur->type == XML_ENTITY_REF_NODE) { - xmlOutputBufferWriteString(buf, "&"); + xmlOutputBufferWrite(buf, 1, "&"); xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, ";"); + xmlOutputBufferWrite(buf, 1, ";"); return; } if (cur->type == XML_CDATA_SECTION_NODE) { @@ -526,17 +697,17 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { while (*end != '\0') { if ((*end == ']') && (*(end + 1) == ']') && (*(end + 2) == '>')) { end = end + 2; - xmlOutputBufferWriteString(buf, "<![CDATA["); + xmlOutputBufferWrite(buf, 9, "<![CDATA["); xmlOutputBufferWrite(buf, end - start, (const char *)start); - xmlOutputBufferWriteString(buf, "]]>"); + xmlOutputBufferWrite(buf, 3, "]]>"); start = end; } end++; } if (start != end) { - xmlOutputBufferWriteString(buf, "<![CDATA["); + xmlOutputBufferWrite(buf, 9, "<![CDATA["); xmlOutputBufferWriteString(buf, (const char *)start); - xmlOutputBufferWriteString(buf, "]]>"); + xmlOutputBufferWrite(buf, 3, "]]>"); } return; } @@ -562,10 +733,10 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { tmp = tmp->next; } } - xmlOutputBufferWriteString(buf, "<"); + xmlOutputBufferWrite(buf, 1, "<"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); - xmlOutputBufferWriteString(buf, ":"); + xmlOutputBufferWrite(buf, 1, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); @@ -576,25 +747,16 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) && (cur->children == NULL) && (!xmlSaveNoEmptyTags)) { - xmlOutputBufferWriteString(buf, "/>"); + xmlOutputBufferWrite(buf, 2, "/>"); ctxt->format = format; return; } - xmlOutputBufferWriteString(buf, ">"); + xmlOutputBufferWrite(buf, 1, ">"); if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { - xmlChar *buffer; - - if (ctxt->encoding == NULL) - buffer = xmlEncodeEntitiesReentrant(ctxt->doc, cur->content); - else - buffer = xmlEncodeSpecialChars(ctxt->doc, cur->content); - if (buffer != NULL) { - xmlOutputBufferWriteString(buf, (const char *)buffer); - xmlFree(buffer); - } + xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape); } if (cur->children != NULL) { - if (ctxt->format) xmlOutputBufferWriteString(buf, "\n"); + if (ctxt->format) xmlOutputBufferWrite(buf, 1, "\n"); if (ctxt->level >= 0) ctxt->level++; xmlNodeListDumpOutput(ctxt, cur->children); if (ctxt->level > 0) ctxt->level--; @@ -604,14 +766,14 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { ctxt->indent_nr : ctxt->level), ctxt->indent); } - xmlOutputBufferWriteString(buf, "</"); + xmlOutputBufferWrite(buf, 2, "</"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); - xmlOutputBufferWriteString(buf, ":"); + xmlOutputBufferWrite(buf, 1, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, ">"); + xmlOutputBufferWrite(buf, 1, ">"); ctxt->format = format; } @@ -637,11 +799,11 @@ xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) { cur->encoding = BAD_CAST ctxt->encoding; buf = ctxt->buf; - xmlOutputBufferWriteString(buf, "<?xml version="); + xmlOutputBufferWrite(buf, 14, "<?xml version="); if (cur->version != NULL) xmlBufferWriteQuotedString(buf->buffer, cur->version); else - xmlOutputBufferWriteString(buf, "\"1.0\""); + xmlOutputBufferWrite(buf, 5, "\"1.0\""); if (ctxt->encoding == NULL) { if (cur->encoding != NULL) encoding = cur->encoding; @@ -650,18 +812,18 @@ xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) { xmlGetCharEncodingName((xmlCharEncoding) cur->charset); } if (encoding != NULL) { - xmlOutputBufferWriteString(buf, " encoding="); + xmlOutputBufferWrite(buf, 10, " encoding="); xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding); } switch (cur->standalone) { case 0: - xmlOutputBufferWriteString(buf, " standalone=\"no\""); + xmlOutputBufferWrite(buf, 16, " standalone=\"no\""); break; case 1: - xmlOutputBufferWriteString(buf, " standalone=\"yes\""); + xmlOutputBufferWrite(buf, 17, " standalone=\"yes\""); break; } - xmlOutputBufferWriteString(buf, "?>\n"); + xmlOutputBufferWrite(buf, 3, "?>\n"); #ifdef LIBXML_HTML_ENABLED dtd = xmlGetIntSubset(cur); @@ -687,7 +849,7 @@ xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) { else #endif xmlNodeDumpOutputInternal(ctxt, child); - xmlOutputBufferWriteString(buf, "\n"); + xmlOutputBufferWrite(buf, 1, "\n"); child = child->next; } } @@ -828,23 +990,23 @@ xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { (xmlStrEqual(parent->name, BAD_CAST "form")) || (xmlStrEqual(parent->name, BAD_CAST "frame")) || (xmlStrEqual(parent->name, BAD_CAST "iframe")))) { - xmlOutputBufferWriteString(buf, " id=\""); - xmlAttrSerializeContent(buf->buffer, ctxt->doc, name); - xmlOutputBufferWriteString(buf, "\""); + xmlOutputBufferWrite(buf, 5, " id=\""); + xmlAttrSerializeContent(buf, name); + xmlOutputBufferWrite(buf, 1, "\""); } } /* * C.7. */ if ((lang != NULL) && (xml_lang == NULL)) { - xmlOutputBufferWriteString(buf, " xml:lang=\""); - xmlAttrSerializeContent(buf->buffer, ctxt->doc, lang); - xmlOutputBufferWriteString(buf, "\""); + xmlOutputBufferWrite(buf, 11, " xml:lang=\""); + xmlAttrSerializeContent(buf, lang); + xmlOutputBufferWrite(buf, 1, "\""); } else if ((xml_lang != NULL) && (lang == NULL)) { - xmlOutputBufferWriteString(buf, " lang=\""); - xmlAttrSerializeContent(buf->buffer, ctxt->doc, xml_lang); - xmlOutputBufferWriteString(buf, "\""); + xmlOutputBufferWrite(buf, 7, " lang=\""); + xmlAttrSerializeContent(buf, xml_lang); + xmlOutputBufferWrite(buf, 1, "\""); } } @@ -876,7 +1038,7 @@ xhtmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { ctxt->indent); xhtmlNodeDumpOutput(ctxt, cur); if (ctxt->format) { - xmlOutputBufferWriteString(buf, "\n"); + xmlOutputBufferWrite(buf, 1, "\n"); } cur = cur->next; } @@ -926,17 +1088,7 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { if (cur->content != NULL) { if ((cur->name == xmlStringText) || (cur->name != xmlStringTextNoenc)) { - xmlChar *buffer; - - if (ctxt->encoding == NULL) - buffer = xmlEncodeEntitiesReentrant(ctxt->doc, - cur->content); - else - buffer = xmlEncodeSpecialChars(ctxt->doc, cur->content); - if (buffer != NULL) { - xmlOutputBufferWriteString(buf, (const char *)buffer); - xmlFree(buffer); - } + xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape); } else { /* * Disable escaping, needed for XSLT @@ -949,32 +1101,32 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { } if (cur->type == XML_PI_NODE) { if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, "<?"); + xmlOutputBufferWrite(buf, 2, "<?"); xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, " "); + xmlOutputBufferWrite(buf, 1, " "); xmlOutputBufferWriteString(buf, (const char *)cur->content); } - xmlOutputBufferWriteString(buf, "?>"); + xmlOutputBufferWrite(buf, 2, "?>"); } else { - xmlOutputBufferWriteString(buf, "<?"); + xmlOutputBufferWrite(buf, 2, "<?"); xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, "?>"); + xmlOutputBufferWrite(buf, 2, "?>"); } return; } if (cur->type == XML_COMMENT_NODE) { if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, "<!--"); + xmlOutputBufferWrite(buf, 4, "<!--"); xmlOutputBufferWriteString(buf, (const char *)cur->content); - xmlOutputBufferWriteString(buf, "-->"); + xmlOutputBufferWrite(buf, 3, "-->"); } return; } if (cur->type == XML_ENTITY_REF_NODE) { - xmlOutputBufferWriteString(buf, "&"); + xmlOutputBufferWrite(buf, 1, "&"); xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, ";"); + xmlOutputBufferWrite(buf, 1, ";"); return; } if (cur->type == XML_CDATA_SECTION_NODE) { @@ -982,17 +1134,17 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { while (*end != '\0') { if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') { end = end + 2; - xmlOutputBufferWriteString(buf, "<![CDATA["); + xmlOutputBufferWrite(buf, 9, "<![CDATA["); xmlOutputBufferWrite(buf, end - start, (const char *)start); - xmlOutputBufferWriteString(buf, "]]>"); + xmlOutputBufferWrite(buf, 3, "]]>"); start = end; } end++; } if (start != end) { - xmlOutputBufferWriteString(buf, "<![CDATA["); + xmlOutputBufferWrite(buf, 9, "<![CDATA["); xmlOutputBufferWriteString(buf, (const char *)start); - xmlOutputBufferWriteString(buf, "]]>"); + xmlOutputBufferWrite(buf, 3, "]]>"); } return; } @@ -1009,10 +1161,10 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { tmp = tmp->next; } } - xmlOutputBufferWriteString(buf, "<"); + xmlOutputBufferWrite(buf, 1, "<"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); - xmlOutputBufferWriteString(buf, ":"); + xmlOutputBufferWrite(buf, 1, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); @@ -1035,33 +1187,24 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { /* * C.2. Empty Elements */ - xmlOutputBufferWriteString(buf, " />"); + xmlOutputBufferWrite(buf, 3, " />"); } else { /* * C.3. Element Minimization and Empty Element Content */ - xmlOutputBufferWriteString(buf, "></"); + xmlOutputBufferWrite(buf, 3, "></"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); - xmlOutputBufferWriteString(buf, ":"); + xmlOutputBufferWrite(buf, 1, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, ">"); + xmlOutputBufferWrite(buf, 1, ">"); } return; } - xmlOutputBufferWriteString(buf, ">"); + xmlOutputBufferWrite(buf, 1, ">"); if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { - xmlChar *buffer; - - if (ctxt->encoding == NULL) - buffer = xmlEncodeEntitiesReentrant(ctxt->doc, cur->content); - else - buffer = xmlEncodeSpecialChars(ctxt->doc, cur->content); - if (buffer != NULL) { - xmlOutputBufferWriteString(buf, (const char *)buffer); - xmlFree(buffer); - } + xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape); } /* @@ -1100,18 +1243,19 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { *(end + 1) == ']' && *(end + 2) == '>') { end = end + 2; - xmlOutputBufferWriteString(buf, "<![CDATA["); + xmlOutputBufferWrite(buf, 9, "<![CDATA["); xmlOutputBufferWrite(buf, end - start, (const char *)start); - xmlOutputBufferWriteString(buf, "]]>"); + xmlOutputBufferWrite(buf, 3, "]]>"); start = end; } end++; } if (start != end) { - xmlOutputBufferWriteString(buf, "<![CDATA["); - xmlOutputBufferWriteString(buf, (const char *)start); - xmlOutputBufferWriteString(buf, "]]>"); + xmlOutputBufferWrite(buf, 9, "<![CDATA["); + xmlOutputBufferWrite(buf, end - start, + (const char *)start); + xmlOutputBufferWrite(buf, 3, "]]>"); } } } else { @@ -1127,24 +1271,28 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { child = child->next; } } else if (cur->children != NULL) { - if (format) xmlOutputBufferWriteString(buf, "\n"); + int indent = ctxt->format; + + if (format) xmlOutputBufferWrite(buf, 1, "\n"); if (ctxt->level >= 0) ctxt->level++; + ctxt->format = format; xhtmlNodeListDumpOutput(ctxt, cur->children); if (ctxt->level > 0) ctxt->level--; + ctxt->format = indent; if ((xmlIndentTreeOutput) && (format)) xmlOutputBufferWrite(buf, ctxt->indent_size * (ctxt->level > ctxt->indent_nr ? ctxt->indent_nr : ctxt->level), ctxt->indent); } - xmlOutputBufferWriteString(buf, "</"); + xmlOutputBufferWrite(buf, 2, "</"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); - xmlOutputBufferWriteString(buf, ":"); + xmlOutputBufferWrite(buf, 1, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, ">"); + xmlOutputBufferWrite(buf, 1, ">"); } #endif @@ -1336,6 +1484,40 @@ xmlSaveClose(xmlSaveCtxtPtr ctxt) return(ret); } +/** + * xmlSaveSetEscape: + * @ctxt: a document saving context + * @escape: the escaping function + * + * Set a custom escaping function to be used for text in element content + * + * Returns 0 if successful or -1 in case of error. + */ +int +xmlSaveSetEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape) +{ + if (ctxt == NULL) return(-1); + ctxt->escape = escape; + return(0); +} + +/** + * xmlSaveSetAttrEscape: + * @ctxt: a document saving context + * @escape: the escaping function + * + * Set a custom escaping function to be used for text in attribute content + * + * Returns 0 if successful or -1 in case of error. + */ +int +xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape) +{ + if (ctxt == NULL) return(-1); + ctxt->escapeAttr = escape; + return(0); +} + /************************************************************************ * * * Public entry points based on buffers * @@ -1352,11 +1534,13 @@ xmlSaveClose(xmlSaveCtxtPtr ctxt) */ void xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc, - xmlAttrPtr attr, const xmlChar *string) { + xmlAttrPtr attr, const xmlChar * string) +{ xmlChar *base, *cur; - if (string == NULL) return; - base = cur = (xmlChar *)string; + if (string == NULL) + return; + base = cur = (xmlChar *) string; while (*cur != 0) { if (*cur == '\n') { if (base != cur) @@ -1364,110 +1548,108 @@ xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc, xmlBufferAdd(buf, BAD_CAST " ", 5); cur++; base = cur; - } else if (*cur == '\r') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST " ", 5); - cur++; - base = cur; - } else if (*cur == '\t') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST "	", 4); - cur++; - base = cur; - } else if (*cur == '"') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST """, 6); - cur++; - base = cur; - } else if (*cur == '<') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST "<", 4); - cur++; - base = cur; - } else if (*cur == '>') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST ">", 4); - cur++; - base = cur; - } else if (*cur == '&') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST "&", 5); + } else if (*cur == '\r') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST " ", 5); + cur++; + base = cur; + } else if (*cur == '\t') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST "	", 4); + cur++; + base = cur; + } else if (*cur == '"') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST """, 6); + cur++; + base = cur; + } else if (*cur == '<') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST "<", 4); + cur++; + base = cur; + } else if (*cur == '>') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST ">", 4); + cur++; + base = cur; + } else if (*cur == '&') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST "&", 5); + cur++; + base = cur; + } else if ((*cur >= 0x80) && ((doc == NULL) || + (doc->encoding == NULL))) { + /* + * We assume we have UTF-8 content. + */ + unsigned char tmp[10]; + int val = 0, l = 1; + + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + if (*cur < 0xC0) { + xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL); + if (doc != NULL) + doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); + xmlSerializeHexCharRef(tmp, *cur); + xmlBufferAdd(buf, (xmlChar *) tmp, -1); cur++; base = cur; - } else if ((*cur >= 0x80) && ((doc == NULL) || - (doc->encoding == NULL))) { - /* - * We assume we have UTF-8 content. - */ - char tmp[10]; - int val = 0, l = 1; - - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - if (*cur < 0xC0) { - xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL); - if (doc != NULL) - doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); - snprintf(tmp, sizeof(tmp), "&#%d;", *cur); - tmp[sizeof(tmp) - 1] = 0; - xmlBufferAdd(buf, (xmlChar *) tmp, -1); - cur++; - base = cur; - continue; - } else if (*cur < 0xE0) { - val = (cur[0]) & 0x1F; - val <<= 6; - val |= (cur[1]) & 0x3F; - l = 2; - } else if (*cur < 0xF0) { - val = (cur[0]) & 0x0F; - val <<= 6; - val |= (cur[1]) & 0x3F; - val <<= 6; - val |= (cur[2]) & 0x3F; - l = 3; - } else if (*cur < 0xF8) { - val = (cur[0]) & 0x07; - val <<= 6; - val |= (cur[1]) & 0x3F; - val <<= 6; - val |= (cur[2]) & 0x3F; - val <<= 6; - val |= (cur[3]) & 0x3F; - l = 4; - } - if ((l == 1) || (!IS_CHAR(val))) { - xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL); - if (doc != NULL) - doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); - snprintf(tmp, sizeof(tmp), "&#%d;", *cur); - tmp[sizeof(tmp) - 1] = 0; - xmlBufferAdd(buf, (xmlChar *) tmp, -1); - cur++; - base = cur; - continue; - } - /* - * We could do multiple things here. Just save - * as a char ref - */ - snprintf(tmp, sizeof(tmp), "&#x%X;", val); - tmp[sizeof(tmp) - 1] = 0; + continue; + } else if (*cur < 0xE0) { + val = (cur[0]) & 0x1F; + val <<= 6; + val |= (cur[1]) & 0x3F; + l = 2; + } else if (*cur < 0xF0) { + val = (cur[0]) & 0x0F; + val <<= 6; + val |= (cur[1]) & 0x3F; + val <<= 6; + val |= (cur[2]) & 0x3F; + l = 3; + } else if (*cur < 0xF8) { + val = (cur[0]) & 0x07; + val <<= 6; + val |= (cur[1]) & 0x3F; + val <<= 6; + val |= (cur[2]) & 0x3F; + val <<= 6; + val |= (cur[3]) & 0x3F; + l = 4; + } + if ((l == 1) || (!IS_CHAR(val))) { + xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL); + if (doc != NULL) + doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); + + xmlSerializeHexCharRef(tmp, *cur); xmlBufferAdd(buf, (xmlChar *) tmp, -1); - cur += l; - base = cur; - } else { cur++; + base = cur; + continue; } + /* + * We could do multiple things here. Just save + * as a char ref + */ + xmlSerializeHexCharRef(tmp, val); + xmlBufferAdd(buf, (xmlChar *) tmp, -1); + cur += l; + base = cur; + } else { + cur++; } - if (base != cur) - xmlBufferAdd(buf, base, cur - base); + } + if (base != cur) + xmlBufferAdd(buf, base, cur - base); } /** |