// 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 #ifdef CCXX_WITHOUT_EXTRAS #include #endif #include #include #include #ifndef CCXX_WITHOUT_EXTRAS #include #endif #include #ifndef WIN32 #include #endif #include // 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_NAMESPACES namespace ost { #ifdef HAVE_SSTREAM using std::stringstream; #else using std::strstream; #endif using std::streambuf; using std::ofstream; using std::ostream; using std::clog; using std::endl; using std::ends; using std::ios; #endif static 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; 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(len < dp && isElement(dbuf[len])) ++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; } bool XMLStream::parse(const char *resource) { bool ret = false; char buffer[1024]; int res; if(resource) if(!open(resource)) return false; parseInit(); while((res = read((unsigned char *)buffer, 1024))) ret = parseChunk(buffer, res); 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 << "" << endl; strBuf << "" << endl; strBuf << "" << member << "" << endl; strBuf << "" << 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 << "" << endl; strBuf << "" << endl; if(fault) strBuf << "" << endl; else strBuf << "" << endl; } void XMLRPC::addMember(const char *name, long value) { #ifdef HAVE_SSTREAM // nothing #else if(!oldStrBuf) return; #endif begStruct(); strBuf << "" << name << "" << endl; strBuf << "" << value << "" << endl; } void XMLRPC::addMember(const char *name, const char *value) { #ifdef HAVE_SSTREAM // nothing #else if(!oldStrBuf) return; #endif begStruct(); strBuf << "" << name << "" << endl; strBuf << "" << value << "" << endl; } void XMLRPC::addMember(const char *name, bool value) { #ifdef HAVE_SSTREAM // nothing #else if(!oldStrBuf) return; #endif begStruct(); strBuf << "" << name << "" << endl; strBuf << ""; if(value) strBuf << "1"; else strBuf << "0"; strBuf << "" << endl; } void XMLRPC::addParam(bool value) { #ifdef HAVE_SSTREAM // nothing #else if(!oldStrBuf) return; #endif endStruct(); if(!fault && !array) strBuf << ""; strBuf << ""; if(value) strBuf << "1"; else strBuf << "0"; strBuf << ""; if(!fault && !array) strBuf << ""; strBuf << endl; } void XMLRPC::addParam(long value) { #ifdef HAVE_SSTREAM // nothing #else if(!oldStrBuf) return; #endif endStruct(); if(!fault && !array) strBuf << ""; strBuf << "" << value << ""; if(!fault && !array) strBuf << ""; strBuf << endl; } void XMLRPC::addParam(const char *value) { #ifdef HAVE_SSTREAM // nothing #else if(!oldStrBuf) return; #endif endStruct(); if(!fault && !array) strBuf << "" << endl; strBuf << "" << value << ""; if(!fault && !array) strBuf << ""; 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 << ""; array++; strBuf << "" << endl; } void XMLRPC::endArray(void) { #ifdef HAVE_SSTREAM // nothing #else if(!oldStrBuf) return; #endif if(!array) return; strBuf << ""; if(!--array) strBuf << ""; strBuf << endl; } void XMLRPC::begStruct(void) { if(structFlag) return; structFlag = true; if(!fault && !array) strBuf << ""; strBuf << "" << endl; } void XMLRPC::endStruct(void) { if(!structFlag) return; strBuf << ""; if(!fault && !array) strBuf << ""; strBuf << endl; structFlag = false; } bool XMLRPC::send(const char *resource) { #ifdef HAVE_SSTREAM // nothing #else if(!oldStrBuf) return false; #endif endStruct(); while(array) { strBuf << "" << endl; --array; } if(!fault) strBuf << "" << endl; else strBuf << "" << endl; if(reply) strBuf << "" << endl << ends; else strBuf << "" << 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) { } XMLStream::~XMLStream() {} #ifdef CCXX_NAMESPACES } #endif /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */