📄 xml.cpp
字号:
// Copyright (C) 2001-2005 Open Source Telecom Corporation.//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.//// As a special exception, you may use this file as part of a free software// library without restriction. Specifically, if other files instantiate// templates or use macros or inline functions from this file, or you compile// this file and link it with other files to produce an executable, this// file does not by itself cause the resulting executable to be covered by// the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by// the GNU General Public License. //// This exception applies only to the code released under the name GNU// Common C++. If you copy code from other releases into a copy of GNU// Common C++, as the General Public License permits, the exception does// not apply to the code that you add in this way. To avoid misleading// anyone as to the status of such modified files, you must delete// this exception notice from them.//// If you write modifications of your own for GNU Common C++, it is your choice// whether to permit this exception to apply to your modifications.// If you do not wish that, delete this exception notice.//#include <cc++/config.h>#ifdef CCXX_WITHOUT_EXTRAS#include <cc++/export.h>#endif#include <cc++/file.h>#include <cc++/thread.h>#include <cc++/exception.h>#ifndef CCXX_WITHOUT_EXTRAS#include <cc++/export.h>#endif#include <cc++/xml.h>#ifndef WIN32#include <syslog.h>#endif#ifdef HAVE_LIBXML#include <libxml/xmlversion.h>#include <libxml/parser.h>#include <libxml/parserInternals.h>#include <libxml/xmlIO.h>#include <cstdarg>#endif// very ugly, but saves a lot of #ifdefs. To understand this, look at// the private members of XMLRPC.#ifndef HAVE_SSTREAM#define strBuf (*oldStrBuf)#endif#ifdef CCXX_NAMESPACESnamespace ost {#ifdef HAVE_SSTREAMusing std::stringstream;#elseusing std::strstream;#endifusing std::streambuf;using std::ofstream;using std::ostream;using std::clog;using std::endl;using std::ends;using std::ios;#endif#ifdef HAVE_LIBXMLextern "C" {static void saxCharacters(XMLStream *xml, const unsigned char *text, int unsigned len){ xml->characters(text, len);}static void saxComment(XMLStream *xml, const unsigned char *text){ unsigned len = strlen((const char *)text); xml->comment(text, len);}static void saxStartDocument(XMLStream *xml){ xml->startDocument();}static void saxEndDocument(XMLStream *xml){ xml->endDocument();}static void saxStartElement(XMLStream *xml, const unsigned char *name, const unsigned char **attributes){ xml->startElement(name, attributes);}static void saxEndElement(XMLStream *xml, const unsigned char *name){ xml->endElement(name);}}#endif#ifndef HAVE_LIBXMLstatic bool isElement(char c){ return isalnum(c) || c == ':' || c == '-' || c == '.' || c == '_';}void XMLStream::putData(char c){ dbuf[dp++] = c; if(dp >= sizeof(dbuf)) { if(ecount) characters((unsigned char *)dbuf, dp); dp = 0; }}void XMLStream::clrData(void){ if(dp && ecount) characters((unsigned char *)dbuf, dp); dp = 0;}void XMLStream::parseInit(void){ state = NONE; dp = 0; ecount = dcount = 0;}bool XMLStream::parseTag(void){ size_t len = dp; const char *data = dbuf; bool end = false, first = false; const unsigned char *attrib[128]; unsigned attr = 0; char *ep; if(*data == '/') { while(--len) { if(!isElement(*(++data))) break; } if(len) return false; dbuf[dp] = 0; endElement((const unsigned char *)(dbuf + 1)); dp = 0; --ecount; if(ecount < 0) return false; if(!ecount) endDocument(); } else if(*data == '!') { dp = 0; return true; // dtd } else if(*data == '?') { if(!strnicmp(data, "?xml version=\"", 14)) { // version info } dp = 0; } else if(!isElement(*data)) return false; else { end = false; if(dbuf[dp - 1] == '/') { --dp; end = true; } len = 0; data = dbuf; while(len < dp) { if(!isElement(*data)) break; ++len; ++data; } if(len == dp) { if(!ecount) startDocument(); ++ecount; attrib[0] = attrib[1] = NULL; dbuf[dp] = 0; startElement((const unsigned char *)dbuf, attrib); if(end) {ending: --ecount; endElement((const unsigned char *)dbuf); if(!ecount) endDocument(); } dp = 0; return true; } if(!ecount) startDocument(); ++ecount; // attributes, name is between data and len for(;;) { while(!isElement(dbuf[len]) && len < dp) { if(!isspace(dbuf[len])) return false; dbuf[len++] = 0; } if(len == dp) break; attrib[attr++] = (const unsigned char *)(dbuf + len); while(isElement(dbuf[len]) && len < dp) ++len; if(len == dp) return false; if(dbuf[len] != '=') return false; dbuf[len++] = 0; if(len == dp) { attrib[attr++] = (const unsigned char *)""; break; } if(isspace(dbuf[len])) { attrib[attr++] = (const unsigned char *)""; continue; } if(dbuf[len] == '\'' || dbuf[len] == '\"') { ep = strchr(dbuf + len + 1, dbuf[len]); if(!ep) return false; attrib[attr++] = (const unsigned char *)dbuf + len + 1; *(ep++) = 0; len = ep - dbuf; continue; } if(!isElement(dbuf[len])) return false; attrib[attr++] = (const unsigned char *)dbuf; while(isElement(dbuf[len]) && len < dp) ++len; if(len == dp) { dbuf[len] = 0; break; } } attrib[attr++] = NULL; attrib[attr++] = NULL; startElement((const unsigned char *)dbuf, attrib); if(end) goto ending; dp = 0; return true; } return true;}bool XMLStream::parseChunk(const char *data, size_t len){ unsigned char cp; while(len--) { switch(state) { case AMP: if((!dp && *data == '#') || isElement(*data)) { dbuf[dp++] = *data; break; } if(*data != ';') return false; dbuf[dp] = 0; if(dbuf[0] == '#') cp = atoi(dbuf + 1); else if(!stricmp(dbuf, "amp")) cp = '&'; else if(!stricmp(dbuf, "lt")) cp = '<'; else if(!stricmp(dbuf, "gt")) cp = '>'; else if(!stricmp(dbuf, "apos")) cp = '`'; else if(!stricmp(dbuf, "quot")) cp = '\"'; else return false; characters(&cp, 1); dp = 0; state = NONE; break; case TAG: if(*data == '>') { state = NONE; if(!parseTag()) return false; } else if(*data == '[' && dp == 7 && !strncmp(dbuf, "![CDATA", 7)) { state = CDATA; } else if(*data == '-' && dp == 2 && !strncmp(dbuf, "!-", 2)) { state = COMMENT; dp = 0; } else if(*data == '[' && !strncmp(dbuf, "!DOCTYPE ", 9)) { state = DTD; dp = 0; } else putData(*data); break; case COMMENT: if(*data == '>' && dp >= 2 && !strncmp(&dbuf[dp - 2], "--", 2)) { dp -= 2; if(dp) comment((unsigned char *)dbuf, dp); dp = 0; state = NONE; } else { dbuf[dp++] = *data; if(dp == sizeof(dbuf)) { comment((unsigned char *)dbuf, dp); dp = 0; } } break; case CDATA: putData(*data); if(dp > 2) if(!strcmp(&dbuf[dp - 3], "]]>")) { dp -= 3; state = NONE; clrData(); } break; case DTD: if(*data == '<') ++dcount; else if(*data == '>' && dcount) --dcount; else if(*data == '>') state = NONE; break; case NONE: if(*data == '<') { clrData(); state = TAG; } else if(ecount && *data == '&') { clrData(); state = AMP; } else if(ecount) putData(*data); } ++data; } return true;}#endifbool XMLStream::parse(const char *resource){ bool ret = false;#ifdef HAVE_LIBXML xmlParserCtxtPtr xml; xmlSAXHandler sax;#endif char buffer[1024]; int res; if(resource) if(!open(resource)) return false;#ifdef HAVE_LIBXML memset(&sax, 0, sizeof(sax)); sax.startDocument = (startDocumentSAXFunc)&saxStartDocument; sax.endDocument = (endDocumentSAXFunc)&saxEndDocument; sax.startElement = (startElementSAXFunc)&saxStartElement; sax.endElement = (endElementSAXFunc)&saxEndElement; sax.characters = (charactersSAXFunc)&saxCharacters; sax.comment = (commentSAXFunc)&saxComment; xml = xmlCreatePushParserCtxt(&sax, this, NULL, 0, NULL); if(!xml) return false;#else parseInit();#endif#ifdef HAVE_LIBXML while((res = read((unsigned char *) buffer, 1024))) xmlParseChunk(xml, buffer, res, 0); xmlParseChunk(xml, buffer, 0, 1); if(xml->wellFormed) ret = true; xml->sax = NULL; xmlFreeParserCtxt(xml);#else while((res = read((unsigned char *)buffer, 1024))) ret = parseChunk(buffer, res);#endif return ret;}XMLRPC::XMLRPC(size_t bufferSize) :XMLStream(){#ifdef HAVE_SSTREAM // nothing#else buffer = new char[bufferSize]; oldStrBuf = NULL; bufSize = bufferSize;#endif}XMLRPC::~XMLRPC(){#ifdef HAVE_SSTREAM // nothing#else if(buffer) delete[] buffer; if(oldStrBuf) delete oldStrBuf;#endif close();}void XMLRPC::invoke(const char *member){#ifdef HAVE_SSTREAM strBuf.str() = "";#else buffer[0] = 0; oldStrBuf = new strstream(buffer,bufSize);#endif structFlag = reply = fault = false; array = 0; strBuf << "<?xml version=\"1.0\"?>" << endl; strBuf << "<methodCall>" << endl; strBuf << "<methodName>" << member << "</methodName>" << endl; strBuf << "<params>" << endl;}void XMLRPC::response(bool f){ reply = true; structFlag = false; fault = f; array = 0;#ifdef HAVE_SSTREAM // nothing#else buffer[0] = 0; oldStrBuf = new strstream(buffer,bufSize);#endif strBuf << "<?xml version=\"1.0\"?>" << endl; strBuf << "<methodResponse>" << endl; if(fault) strBuf << "<fault>" << endl; else strBuf << "<params>" << endl;}void XMLRPC::addMember(const char *name, long value){#ifdef HAVE_SSTREAM // nothing#else if(!oldStrBuf) return;#endif begStruct(); strBuf << "<member><name>" << name << "</name>" << endl; strBuf << "<value><i4>" << value << "</i4></value></member>" << endl;}void XMLRPC::addMember(const char *name, const char *value){#ifdef HAVE_SSTREAM // nothing#else if(!oldStrBuf) return;#endif begStruct(); strBuf << "<member><name>" << name << "</name>" << endl; strBuf << "<value><string>" << value << "</string></value></member>" << endl;}void XMLRPC::addMember(const char *name, bool value){#ifdef HAVE_SSTREAM // nothing#else if(!oldStrBuf) return;#endif begStruct(); strBuf << "<member><name>" << name << "</name>" << endl; strBuf << "<value><boolean>"; if(value) strBuf << "1"; else strBuf << "0"; strBuf << "</boolean></value></member>" << endl;}void XMLRPC::addParam(bool value){#ifdef HAVE_SSTREAM // nothing#else if(!oldStrBuf) return;#endif endStruct(); if(!fault && !array) strBuf << "<param>"; strBuf << "<value><boolean>"; if(value) strBuf << "1"; else strBuf << "0"; strBuf << "</boolean></value>"; if(!fault && !array) strBuf << "</param>"; strBuf << endl;}void XMLRPC::addParam(long value){#ifdef HAVE_SSTREAM // nothing#else if(!oldStrBuf) return;#endif endStruct(); if(!fault && !array) strBuf << "<param>"; strBuf << "<value><i4>" << value << "</i4></value>"; if(!fault && !array) strBuf << "</param>"; strBuf << endl;}void XMLRPC::addParam(const char *value){#ifdef HAVE_SSTREAM // nothing#else if(!oldStrBuf) return;#endif endStruct(); if(!fault && !array) strBuf << "<param>" << endl; strBuf << "<value><string>" << value << "</string></value>"; if(!fault && !array) strBuf << "</param>"; strBuf << endl;}void XMLRPC::begArray(void){#ifdef HAVE_SSTREAM // nothing#else if(!oldStrBuf) return;#endif if(fault) //do not include arrays in fault responses. return; if(!array) strBuf << "<param>"; array++; strBuf << "<array><data>" << endl;}void XMLRPC::endArray(void){#ifdef HAVE_SSTREAM // nothing#else if(!oldStrBuf) return;#endif if(!array) return; strBuf << "</data></array>"; if(!--array) strBuf << "</param>"; strBuf << endl;}void XMLRPC::begStruct(void){ if(structFlag) return; structFlag = true; if(!fault && !array) strBuf << "<param>"; strBuf << "<struct><value>" << endl;}void XMLRPC::endStruct(void){ if(!structFlag) return; strBuf << "</struct></value>"; if(!fault && !array) strBuf << "</param>"; strBuf << endl; structFlag = false;}bool XMLRPC::send(const char *resource){#ifdef HAVE_SSTREAM // nothing#else if(!oldStrBuf) return false;#endif endStruct(); while(array) { strBuf << "</data></array>" << endl; --array; } if(!fault) strBuf << "</params>" << endl; if(reply) strBuf << "</methodResponse>" << endl << ends; else strBuf << "</methodCall>" << endl << ends; bool result;#ifdef HAVE_SSTREAM result = post(resource, strBuf.str().c_str()); strBuf.str("");#else delete oldStrBuf; oldStrBuf = NULL; result = post(resource, (const char *)buffer);#endif return result;}bool XMLStream::open(const char *resource){ return true;}void XMLStream::close(void){}Slog::Level XMLStream::getLogging(void){ return Slog::levelCritical;}void XMLStream::comment(const unsigned char *text, size_t len){}void XMLStream::startDocument(void){}void XMLStream::endDocument(void){}#ifdef CCXX_NAMESPACES}#endif/** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -