📄 xmlwriter.c.svn-base
字号:
/* * xmlwriter.c: XML text writer implementation * * For license and disclaimer see the license and disclaimer of * libxml2. * * alfred@mickautsch.de */#define IN_LIBXML#include <string.h>#include "libxml.h"#include <libxml/xmlmemory.h>#include <libxml/parser.h>#include <libxml/uri.h>#include <libxml/HTMLtree.h>#ifdef LIBXML_WRITER_ENABLED#include <libxml/xmlwriter.h>#include "wincecompat.h"#define BUFSIZ 512#define B64LINELEN 72#define B64CRLF "\r\n"/* * Types are kept private */typedef enum { XML_TEXTWRITER_NONE = 0, XML_TEXTWRITER_NAME, XML_TEXTWRITER_ATTRIBUTE, XML_TEXTWRITER_TEXT, XML_TEXTWRITER_PI, XML_TEXTWRITER_PI_TEXT, XML_TEXTWRITER_CDATA, XML_TEXTWRITER_DTD, XML_TEXTWRITER_DTD_TEXT, XML_TEXTWRITER_DTD_ELEM, XML_TEXTWRITER_DTD_ELEM_TEXT, XML_TEXTWRITER_DTD_ATTL, XML_TEXTWRITER_DTD_ATTL_TEXT, XML_TEXTWRITER_DTD_ENTY, /* entity */ XML_TEXTWRITER_DTD_ENTY_TEXT, XML_TEXTWRITER_DTD_PENT, /* parameter entity */ XML_TEXTWRITER_COMMENT} xmlTextWriterState;typedef struct _xmlTextWriterStackEntry xmlTextWriterStackEntry;struct _xmlTextWriterStackEntry { xmlChar *name; xmlTextWriterState state;};typedef struct _xmlTextWriterNsStackEntry xmlTextWriterNsStackEntry;struct _xmlTextWriterNsStackEntry { xmlChar *prefix; xmlChar *uri; xmlLinkPtr elem;};struct _xmlTextWriter { xmlOutputBufferPtr out; /* output buffer */ xmlListPtr nodes; /* element name stack */ xmlListPtr nsstack; /* name spaces stack */ int level; int indent; /* enable indent */ int doindent; /* internal indent flag */ xmlChar *ichar; /* indent character */ char qchar; /* character used for quoting attribute values */ xmlParserCtxtPtr ctxt;};static void xmlFreeTextWriterStackEntry(xmlLinkPtr lk);static int xmlCmpTextWriterStackEntry(const void *data0, const void *data1);static void xmlFreeTextWriterNsStackEntry(xmlLinkPtr lk);static int xmlCmpTextWriterNsStackEntry(const void *data0, const void *data1);static int xmlTextWriterWriteMemCallback(void *context, const xmlChar * str, int len);static int xmlTextWriterCloseMemCallback(void *context);static int xmlTextWriterWriteDocCallback(void *context, const xmlChar * str, int len);static int xmlTextWriterCloseDocCallback(void *context);static xmlChar *xmlTextWriterVSprintf(const char *format, va_list argptr);static int xmlOutputBufferWriteBase64(xmlOutputBufferPtr out, int len, const unsigned char *data);static void xmlTextWriterStartDocumentCallback(void *ctx);static int xmlTextWriterWriteIndent(xmlTextWriterPtr writer);static int xmlTextWriterHandleStateDependencies(xmlTextWriterPtr writer, xmlTextWriterStackEntry * p);/** * xmlNewTextWriter: * @out: an xmlOutputBufferPtr * * Create a new xmlNewTextWriter structure using an xmlOutputBufferPtr * * Returns the new xmlTextWriterPtr or NULL in case of error */xmlTextWriterPtrxmlNewTextWriter(xmlOutputBufferPtr out){ xmlTextWriterPtr ret; ret = (xmlTextWriterPtr) xmlMalloc(sizeof(xmlTextWriter)); if (ret == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriter : out of memory!\n"); return NULL; } memset(ret, 0, (size_t) sizeof(xmlTextWriter)); ret->nodes = xmlListCreate((xmlListDeallocator) xmlFreeTextWriterStackEntry, (xmlListDataCompare) xmlCmpTextWriterStackEntry); if (ret->nodes == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriter : out of memory!\n"); xmlFree(ret); return NULL; } ret->nsstack = xmlListCreate((xmlListDeallocator) xmlFreeTextWriterNsStackEntry, (xmlListDataCompare) xmlCmpTextWriterNsStackEntry); if (ret->nsstack == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriter : out of memory!\n"); xmlListDelete(ret->nodes); xmlFree(ret); return NULL; } ret->out = out; ret->ichar = xmlStrdup(BAD_CAST " "); ret->qchar = '"'; if (!ret->ichar) { xmlListDelete(ret->nodes); xmlListDelete(ret->nsstack); xmlFree(ret); xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriter : out of memory!\n"); return NULL; } return ret;}/** * xmlNewTextWriterFilename: * @uri: the URI of the resource for the output * @compression: compress the output? * * Create a new xmlNewTextWriter structure with @uri as output * * Returns the new xmlTextWriterPtr or NULL in case of error */xmlTextWriterPtrxmlNewTextWriterFilename(const char *uri, int compression){ xmlTextWriterPtr ret; xmlOutputBufferPtr out; out = xmlOutputBufferCreateFilename(uri, NULL, compression); if (out == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterFilename : out of memory!\n"); return NULL; } ret = xmlNewTextWriter(out); if (ret == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterFilename : out of memory!\n"); xmlOutputBufferClose(out); return NULL; } ret->indent = 0; ret->doindent = 0; return ret;}/** * xmlNewTextWriterMemory: * @buf: xmlBufferPtr * @compression: compress the output? * * Create a new xmlNewTextWriter structure with @buf as output * TODO: handle compression * * Returns the new xmlTextWriterPtr or NULL in case of error */xmlTextWriterPtrxmlNewTextWriterMemory(xmlBufferPtr buf, int compression ATTRIBUTE_UNUSED){ xmlTextWriterPtr ret; xmlOutputBufferPtr out;/*::todo handle compression */ out = xmlOutputBufferCreateIO((xmlOutputWriteCallback) xmlTextWriterWriteMemCallback, (xmlOutputCloseCallback) xmlTextWriterCloseMemCallback, (void *) buf, NULL); if (out == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterMemory : out of memory!\n"); return NULL; } ret = xmlNewTextWriter(out); if (ret == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterMemory : out of memory!\n"); xmlOutputBufferClose(out); return NULL; } return ret;}/** * xmlNewTextWriterPushParser: * @ctxt: xmlParserCtxtPtr to hold the new XML document tree * @compression: compress the output? * * Create a new xmlNewTextWriter structure with @ctxt as output * TODO: handle compression * * Returns the new xmlTextWriterPtr or NULL in case of error */xmlTextWriterPtrxmlNewTextWriterPushParser(xmlParserCtxtPtr ctxt, int compression ATTRIBUTE_UNUSED){ xmlTextWriterPtr ret; xmlOutputBufferPtr out; if (ctxt == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterPushParser : invalid context!\n"); return NULL; } out = xmlOutputBufferCreateIO((xmlOutputWriteCallback) xmlTextWriterWriteDocCallback, (xmlOutputCloseCallback) xmlTextWriterCloseDocCallback, (void *) ctxt, NULL); if (out == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterPushParser : error at xmlOutputBufferCreateIO!\n"); return NULL; } ret = xmlNewTextWriter(out); if (ret == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterPushParser : error at xmlNewTextWriter!\n"); xmlOutputBufferClose(out); return NULL; } ret->ctxt = ctxt; return ret;}/** * xmlNewTextWriterDoc: * @doc: address of a xmlDocPtr to hold the new XML document tree * @compression: compress the output? * * Create a new xmlNewTextWriter structure with @*doc as output * * Returns the new xmlTextWriterPtr or NULL in case of error */xmlTextWriterPtrxmlNewTextWriterDoc(xmlDocPtr * doc, int compression){ xmlTextWriterPtr ret; xmlSAXHandler saxHandler; xmlParserCtxtPtr ctxt; memset(&saxHandler, '\0', sizeof(saxHandler)); xmlSAX2InitDefaultSAXHandler(&saxHandler, 1); saxHandler.startDocument = xmlTextWriterStartDocumentCallback; saxHandler.startElement = xmlSAX2StartElement; saxHandler.endElement = xmlSAX2EndElement; ctxt = xmlCreatePushParserCtxt(&saxHandler, NULL, NULL, 0, NULL); if (ctxt == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterDoc : error at xmlCreatePushParserCtxt!\n"); return NULL; } ctxt->myDoc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION); if (ctxt->myDoc == NULL) { xmlFreeParserCtxt(ctxt); xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterDoc : error at xmlNewDoc!\n"); return NULL; } ret = xmlNewTextWriterPushParser(ctxt, compression); if (ret == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterDoc : error at xmlNewTextWriterPushParser!\n"); return NULL; } xmlSetDocCompressMode(ctxt->myDoc, compression); if (doc != NULL) *doc = ctxt->myDoc; return ret;}/** * xmlNewTextWriterTree: * @doc: xmlDocPtr * @node: xmlNodePtr or NULL for doc->children * @compression: compress the output? * * Create a new xmlNewTextWriter structure with @doc as output * starting at @node * * Returns the new xmlTextWriterPtr or NULL in case of error */xmlTextWriterPtrxmlNewTextWriterTree(xmlDocPtr doc, xmlNodePtr node, int compression){ xmlTextWriterPtr ret; xmlSAXHandler saxHandler; xmlParserCtxtPtr ctxt; if (doc == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterTree : invalid document tree!\n"); return NULL; } memset(&saxHandler, '\0', sizeof(saxHandler)); xmlSAX2InitDefaultSAXHandler(&saxHandler, 1); saxHandler.startDocument = xmlTextWriterStartDocumentCallback; saxHandler.startElement = xmlSAX2StartElement; saxHandler.endElement = xmlSAX2EndElement; ctxt = xmlCreatePushParserCtxt(&saxHandler, NULL, NULL, 0, NULL); if (ctxt == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterDoc : error at xmlCreatePushParserCtxt!\n"); return NULL; } ret = xmlNewTextWriterPushParser(ctxt, compression); if (ret == NULL) { xmlFreeParserCtxt(ctxt); xmlGenericError(xmlGenericErrorContext, "xmlNewTextWriterDoc : error at xmlNewTextWriterPushParser!\n"); return NULL; } ctxt->myDoc = doc; ctxt->node = node; xmlSetDocCompressMode(doc, compression); return ret;}/** * xmlFreeTextWriter: * @writer: the xmlTextWriterPtr * * Deallocate all the resources associated to the writer */voidxmlFreeTextWriter(xmlTextWriterPtr writer){ if (writer == NULL) return; if (writer->out != NULL) xmlOutputBufferClose(writer->out); if (writer->nodes != NULL) xmlListDelete(writer->nodes); if (writer->nsstack != NULL) xmlListDelete(writer->nsstack); if (writer->ctxt != NULL) xmlFreeParserCtxt(writer->ctxt); if (writer->ichar != NULL) xmlFree(writer->ichar); xmlFree(writer);}/** * xmlTextWriterStartDocument: * @writer: the xmlTextWriterPtr * @version: the xml version ("1.0") or NULL for default ("1.0") * @encoding: the encoding or NULL for default * @standalone: "yes" or "no" or NULL for default * * Start a new xml document * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */intxmlTextWriterStartDocument(xmlTextWriterPtr writer, const char *version, const char *encoding, const char *standalone){ int count; int sum; xmlLinkPtr lk; xmlCharEncodingHandlerPtr encoder; if ((writer == NULL) || (writer->out == NULL)) { xmlGenericError(xmlGenericErrorContext, "xmlTextWriterStartDocument : invalid writer!\n"); return -1; } lk = xmlListFront(writer->nodes); if ((lk != NULL) && (xmlLinkGetData(lk) != NULL)) { xmlGenericError(xmlGenericErrorContext, "xmlTextWriterStartDocument : not allowed in this context!\n"); return -1; } encoder = NULL; if (encoding != NULL) { encoder = xmlFindCharEncodingHandler(encoding); if (encoder == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlTextWriterStartDocument : out of memory!\n"); return -1; } } writer->out->encoder = encoder; if (encoder != NULL) { writer->out->conv = xmlBufferCreateSize(4000); xmlCharEncOutFunc(encoder, writer->out->conv, NULL); } else writer->out->conv = NULL; sum = 0; count = xmlOutputBufferWriteString(writer->out, "<?xml version="); if (count < 0) return -1; sum += count; count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); if (count < 0) return -1; sum += count; if (version != 0) count = xmlOutputBufferWriteString(writer->out, version); else count = xmlOutputBufferWriteString(writer->out, "1.0"); if (count < 0) return -1; sum += count; count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); if (count < 0) return -1; sum += count; if (writer->out->encoder != 0) { count = xmlOutputBufferWriteString(writer->out, " encoding="); if (count < 0) return -1; sum += count; count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); if (count < 0) return -1; sum += count; count =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -