$search
00001 00002 #include "XmlRpcUtil.h" 00003 00004 #ifndef MAKEDEPEND 00005 # include <ctype.h> 00006 # include <iostream> 00007 # include <stdarg.h> 00008 # include <stdio.h> 00009 # include <string.h> 00010 #endif 00011 00012 #include "XmlRpc.h" 00013 00014 using namespace XmlRpc; 00015 00016 00017 //#define USE_WINDOWS_DEBUG // To make the error and log messages go to VC++ debug output 00018 #ifdef USE_WINDOWS_DEBUG 00019 #define WIN32_LEAN_AND_MEAN 00020 #include <windows.h> 00021 #endif 00022 00023 // Version id 00024 const char XmlRpc::XMLRPC_VERSION[] = "XMLRPC++ 0.7"; 00025 00026 // Default log verbosity: 0 for no messages through 5 (writes everything) 00027 int XmlRpcLogHandler::_verbosity = 0; 00028 00029 // Default log handler 00030 static class DefaultLogHandler : public XmlRpcLogHandler { 00031 public: 00032 00033 void log(int level, const char* msg) { 00034 #ifdef USE_WINDOWS_DEBUG 00035 if (level <= _verbosity) { OutputDebugString(msg); OutputDebugString("\n"); } 00036 #else 00037 if (level <= _verbosity) std::cout << msg << std::endl; 00038 #endif 00039 } 00040 00041 } defaultLogHandler; 00042 00043 // Message log singleton 00044 XmlRpcLogHandler* XmlRpcLogHandler::_logHandler = &defaultLogHandler; 00045 00046 00047 // Default error handler 00048 static class DefaultErrorHandler : public XmlRpcErrorHandler { 00049 public: 00050 00051 #ifdef USE_WINDOWS_DEBUG 00052 void error(const char* msg) { 00053 OutputDebugString(msg); OutputDebugString("\n"); 00054 #else 00055 void error(const char*) { 00056 #endif 00057 // As far as I can tell, throwing an exception here is a bug, unless 00058 // the intention is that the program should exit. Throughout the code, 00059 // calls to error() are followed by cleanup code that does things like 00060 // closing a failed socket. Thus it would seem that it should be 00061 // possible to continue execution. But if the user just catches the 00062 // exception that's thrown here, the library ends up in a bogus state. 00063 // So I'm commenting out the throw. - BPG 00064 // 00065 //throw std::runtime_error(msg); 00066 } 00067 } defaultErrorHandler; 00068 00069 00070 // Error handler singleton 00071 XmlRpcErrorHandler* XmlRpcErrorHandler::_errorHandler = &defaultErrorHandler; 00072 00073 00074 // Easy API for log verbosity 00075 int XmlRpc::getVerbosity() { return XmlRpcLogHandler::getVerbosity(); } 00076 void XmlRpc::setVerbosity(int level) { XmlRpcLogHandler::setVerbosity(level); } 00077 00078 00079 00080 void XmlRpcUtil::log(int level, const char* fmt, ...) 00081 { 00082 if (level <= XmlRpcLogHandler::getVerbosity()) 00083 { 00084 va_list va; 00085 char buf[1024]; 00086 va_start( va, fmt); 00087 vsnprintf(buf,sizeof(buf)-1,fmt,va); 00088 buf[sizeof(buf)-1] = 0; 00089 XmlRpcLogHandler::getLogHandler()->log(level, buf); 00090 } 00091 } 00092 00093 00094 void XmlRpcUtil::error(const char* fmt, ...) 00095 { 00096 va_list va; 00097 va_start(va, fmt); 00098 char buf[1024]; 00099 vsnprintf(buf,sizeof(buf)-1,fmt,va); 00100 buf[sizeof(buf)-1] = 0; 00101 XmlRpcErrorHandler::getErrorHandler()->error(buf); 00102 } 00103 00104 00105 // Returns contents between <tag> and </tag>, updates offset to char after </tag> 00106 std::string 00107 XmlRpcUtil::parseTag(const char* tag, std::string const& xml, int* offset) 00108 { 00109 if (*offset >= int(xml.length())) return std::string(); 00110 size_t istart = xml.find(tag, *offset); 00111 if (istart == std::string::npos) return std::string(); 00112 istart += strlen(tag); 00113 std::string etag = "</"; 00114 etag += tag + 1; 00115 size_t iend = xml.find(etag, istart); 00116 if (iend == std::string::npos) return std::string(); 00117 00118 *offset = int(iend + etag.length()); 00119 return xml.substr(istart, iend-istart); 00120 } 00121 00122 00123 // Returns true if the tag is found and updates offset to the char after the tag 00124 bool 00125 XmlRpcUtil::findTag(const char* tag, std::string const& xml, int* offset) 00126 { 00127 if (*offset >= int(xml.length())) return false; 00128 size_t istart = xml.find(tag, *offset); 00129 if (istart == std::string::npos) 00130 return false; 00131 00132 *offset = int(istart + strlen(tag)); 00133 return true; 00134 } 00135 00136 00137 // Returns true if the tag is found at the specified offset (modulo any whitespace) 00138 // and updates offset to the char after the tag 00139 bool 00140 XmlRpcUtil::nextTagIs(const char* tag, std::string const& xml, int* offset) 00141 { 00142 if (*offset >= int(xml.length())) return false; 00143 const char* cp = xml.c_str() + *offset; 00144 int nc = 0; 00145 while (*cp && isspace(*cp)) { 00146 ++cp; 00147 ++nc; 00148 } 00149 00150 int len = int(strlen(tag)); 00151 if (*cp && (strncmp(cp, tag, len) == 0)) { 00152 *offset += nc + len; 00153 return true; 00154 } 00155 return false; 00156 } 00157 00158 // Returns the next tag and updates offset to the char after the tag, or empty string 00159 // if the next non-whitespace character is not '<' 00160 std::string 00161 XmlRpcUtil::getNextTag(std::string const& xml, int* offset) 00162 { 00163 if (*offset >= int(xml.length())) return std::string(); 00164 00165 size_t pos = *offset; 00166 const char* cp = xml.c_str() + pos; 00167 while (*cp && isspace(*cp)) { 00168 ++cp; 00169 ++pos; 00170 } 00171 00172 if (*cp != '<') return std::string(); 00173 00174 std::string s; 00175 do { 00176 s += *cp; 00177 ++pos; 00178 } while (*cp++ != '>' && *cp != 0); 00179 00180 *offset = int(pos); 00181 return s; 00182 } 00183 00184 00185 00186 // xml encodings (xml-encoded entities are preceded with '&') 00187 static const char AMP = '&'; 00188 static const char rawEntity[] = { '<', '>', '&', '\'', '\"', 0 }; 00189 static const char* xmlEntity[] = { "lt;", "gt;", "amp;", "apos;", "quot;", 0 }; 00190 static const int xmlEntLen[] = { 3, 3, 4, 5, 5 }; 00191 00192 00193 // Replace xml-encoded entities with the raw text equivalents. 00194 00195 std::string 00196 XmlRpcUtil::xmlDecode(const std::string& encoded) 00197 { 00198 std::string::size_type iAmp = encoded.find(AMP); 00199 if (iAmp == std::string::npos) 00200 return encoded; 00201 00202 std::string decoded(encoded, 0, iAmp); 00203 std::string::size_type iSize = encoded.size(); 00204 decoded.reserve(iSize); 00205 00206 const char* ens = encoded.c_str(); 00207 while (iAmp != iSize) { 00208 if (encoded[iAmp] == AMP && iAmp+1 < iSize) { 00209 int iEntity; 00210 for (iEntity=0; xmlEntity[iEntity] != 0; ++iEntity) 00211 //if (encoded.compare(iAmp+1, xmlEntLen[iEntity], xmlEntity[iEntity]) == 0) 00212 if (strncmp(ens+iAmp+1, xmlEntity[iEntity], xmlEntLen[iEntity]) == 0) 00213 { 00214 decoded += rawEntity[iEntity]; 00215 iAmp += xmlEntLen[iEntity]+1; 00216 break; 00217 } 00218 if (xmlEntity[iEntity] == 0) // unrecognized sequence 00219 decoded += encoded[iAmp++]; 00220 00221 } else { 00222 decoded += encoded[iAmp++]; 00223 } 00224 } 00225 00226 return decoded; 00227 } 00228 00229 00230 // Replace raw text with xml-encoded entities. 00231 00232 std::string 00233 XmlRpcUtil::xmlEncode(const std::string& raw) 00234 { 00235 std::string::size_type iRep = raw.find_first_of(rawEntity); 00236 if (iRep == std::string::npos) 00237 return raw; 00238 00239 std::string encoded(raw, 0, iRep); 00240 std::string::size_type iSize = raw.size(); 00241 00242 while (iRep != iSize) { 00243 int iEntity; 00244 for (iEntity=0; rawEntity[iEntity] != 0; ++iEntity) 00245 if (raw[iRep] == rawEntity[iEntity]) 00246 { 00247 encoded += AMP; 00248 encoded += xmlEntity[iEntity]; 00249 break; 00250 } 00251 if (rawEntity[iEntity] == 0) 00252 encoded += raw[iRep]; 00253 ++iRep; 00254 } 00255 return encoded; 00256 } 00257 00258 00259