📄 xmlsave.c.svn-base
字号:
/* * xmlsave.c: Implemetation of the document serializer * * See Copyright for the status of this software. * * daniel@veillard.com */#define IN_LIBXML#include "libxml.h"#include <string.h>#include <libxml/xmlmemory.h>#include <libxml/parserInternals.h>#include <libxml/tree.h>#include <libxml/xmlsave.h>#define MAX_INDENT 60#include <libxml/HTMLtree.h>/************************************************************************ * * * XHTML detection * * * ************************************************************************/#define XHTML_STRICT_PUBLIC_ID BAD_CAST \ "-//W3C//DTD XHTML 1.0 Strict//EN"#define XHTML_STRICT_SYSTEM_ID BAD_CAST \ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"#define XHTML_FRAME_PUBLIC_ID BAD_CAST \ "-//W3C//DTD XHTML 1.0 Frameset//EN"#define XHTML_FRAME_SYSTEM_ID BAD_CAST \ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"#define XHTML_TRANS_PUBLIC_ID BAD_CAST \ "-//W3C//DTD XHTML 1.0 Transitional//EN"#define XHTML_TRANS_SYSTEM_ID BAD_CAST \ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"/** * xmlIsXHTML: * @systemID: the system identifier * @publicID: the public identifier * * Try to find if the document correspond to an XHTML DTD * * Returns 1 if true, 0 if not and -1 in case of error */intxmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) { if ((systemID == NULL) && (publicID == NULL)) return(-1); if (publicID != NULL) { if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1); if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1); if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1); } if (systemID != NULL) { if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1); if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1); if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1); } return(0);}#ifdef LIBXML_OUTPUT_ENABLED#define TODO \ xmlGenericError(xmlGenericErrorContext, \ "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__);struct _xmlSaveCtxt { void *_private; int type; int fd; const xmlChar *filename; const xmlChar *encoding; xmlCharEncodingHandlerPtr handler; xmlOutputBufferPtr buf; xmlDocPtr doc; int options; int level; int format; 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 */};/************************************************************************ * * * Output error handlers * * * ************************************************************************//** * xmlSaveErrMemory: * @extra: extra informations * * Handle an out of memory condition */static voidxmlSaveErrMemory(const char *extra){ __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);}/** * xmlSaveErr: * @code: the error number * @node: the location of the error. * @extra: extra informations * * Handle an out of memory condition */static voidxmlSaveErr(int code, xmlNodePtr node, const char *extra){ const char *msg = NULL; switch(code) { case XML_SAVE_NOT_UTF8: msg = "string is not in UTF-8"; break; case XML_SAVE_CHAR_INVALID: msg = "invalid character value"; break; case XML_SAVE_UNKNOWN_ENCODING: msg = "unknown encoding %s"; break; case XML_SAVE_NO_DOCTYPE: msg = "document has no DOCTYPE"; break; default: msg = "unexpected error number"; } __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, 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 intxmlEscapeEntities(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 * * * ************************************************************************//** * xmlSaveCtxtInit: * @ctxt: the saving context * * Initialize a saving context */static voidxmlSaveCtxtInit(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 { ctxt->indent_size = xmlStrlen((const xmlChar *) xmlTreeIndentString); ctxt->indent_nr = MAX_INDENT / ctxt->indent_size; for (i = 0;i < ctxt->indent_nr;i++) memcpy(&ctxt->indent[i * ctxt->indent_size], xmlTreeIndentString, ctxt->indent_size); ctxt->indent[ctxt->indent_nr * ctxt->indent_size] = 0; }}/** * xmlFreeSaveCtxt: * * Free a saving context, destroying the ouptut in any remaining buffer */static voidxmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt){ if (ctxt == NULL) return; if (ctxt->encoding != NULL) xmlFree((char *) ctxt->encoding); if (ctxt->buf != NULL) xmlOutputBufferClose(ctxt->buf); xmlFree(ctxt);}/** * xmlNewSaveCtxt: * * Create a new saving context * * Returns the new structure or NULL in case of error */static xmlSaveCtxtPtrxmlNewSaveCtxt(const char *encoding, int options){ xmlSaveCtxtPtr ret; ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt)); if (ret == NULL) { xmlSaveErrMemory("creating saving context"); return ( NULL ); } memset(ret, 0, sizeof(xmlSaveCtxt)); ret->options = options; if (encoding != NULL) { ret->handler = xmlFindCharEncodingHandler(encoding); if (ret->handler == NULL) { xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); xmlFreeSaveCtxt(ret); return(NULL); } ret->encoding = xmlStrdup((const xmlChar *)encoding); ret->escape = xmlEscapeEntities; } xmlSaveCtxtInit(ret); return(ret);}/************************************************************************ * * * Dumping XML tree content to a simple buffer * * * ************************************************************************//** * xmlAttrSerializeContent: * @buf: the XML buffer output * @doc: the document * @attr: the attribute pointer * * Serialize the attribute in the buffer */static voidxmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr){ xmlNodePtr children; children = attr->children; while (children != NULL) { switch (children->type) { case XML_TEXT_NODE: xmlAttrSerializeTxtContent(buf->buffer, attr->doc, attr, children->content); break; case XML_ENTITY_REF_NODE: xmlBufferAdd(buf->buffer, BAD_CAST "&", 1); xmlBufferAdd(buf->buffer, children->name, xmlStrlen(children->name)); xmlBufferAdd(buf->buffer, BAD_CAST ";", 1); break; default: /* should not happen unless we have a badly built tree */ break; } children = children->next; }}/************************************************************************ * * * Dumping XML tree content to an I/O output buffer * * * ************************************************************************/#ifdef LIBXML_HTML_ENABLEDstatic voidxhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);#endifstatic void xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);/** * xmlNsDumpOutput: * @buf: the XML buffer output * @cur: a namespace * * Dump a local Namespace definition. * Should be called in the context of attributes dumps. */static voidxmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { if (cur == NULL) return; if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) { if (xmlStrEqual(cur->prefix, BAD_CAST "xml")) return; /* Within the context of an element attributes */ if (cur->prefix != NULL) { xmlOutputBufferWrite(buf, 7, " xmlns:"); xmlOutputBufferWriteString(buf, (const char *)cur->prefix); } else xmlOutputBufferWrite(buf, 6, " xmlns"); xmlOutputBufferWrite(buf, 1, "="); xmlBufferWriteQuotedString(buf->buffer, cur->href); }}/** * xmlNsListDumpOutput: * @buf: the XML buffer output * @cur: the first namespace * * Dump a list of local Namespace definitions. * Should be called in the context of attributes dumps. */voidxmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { while (cur != NULL) { xmlNsDumpOutput(buf, cur); cur = cur->next; }}/** * xmlDtdDumpOutput: * @buf: the XML buffer output * @dtd: the pointer to the DTD * * Dump the XML document DTD, if any. */static voidxmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) { xmlOutputBufferPtr buf; int format, level; xmlDocPtr doc; if (dtd == NULL) return; if ((ctxt == NULL) || (ctxt->buf == NULL)) return; buf = ctxt->buf; xmlOutputBufferWrite(buf, 10, "<!DOCTYPE "); xmlOutputBufferWriteString(buf, (const char *)dtd->name); if (dtd->ExternalID != NULL) { xmlOutputBufferWrite(buf, 8, " PUBLIC "); xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID); xmlOutputBufferWrite(buf, 1, " "); xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID); } else if (dtd->SystemID != NULL) { 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)) { xmlOutputBufferWrite(buf, 1, ">"); return; } xmlOutputBufferWrite(buf, 3, " [\n"); format = ctxt->format; level = ctxt->level; doc = ctxt->doc; ctxt->format = 0; ctxt->level = -1; ctxt->doc = dtd->doc; xmlNodeListDumpOutput(ctxt, dtd->children); ctxt->format = format; ctxt->level = level; ctxt->doc = doc; xmlOutputBufferWrite(buf, 2, "]>");}/** * xmlAttrDumpOutput: * @buf: the XML buffer output * @cur: the attribute pointer * * Dump an XML attribute */static voidxmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { xmlOutputBufferPtr buf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -