1 2 #include "XmlRpcUtil.h" 3 4 #ifndef MAKEDEPEND 5 # include <ctype.h> 6 # include <iostream> 7 # include <stdarg.h> 8 # include <stdio.h> 9 # include <string.h> 10 #endif 11 12 #include "XmlRpc.h" 13 14 using namespace XmlRpc; 15 16 17 //#define USE_WINDOWS_DEBUG // To make the error and log messages go to VC++ debug output 18 #ifdef USE_WINDOWS_DEBUG 19 #define WIN32_LEAN_AND_MEAN 20 #include <windows.h> 21 #endif 22 23 // Version id 24 const char XmlRpc::XMLRPC_VERSION[] = "XMLRPC++ 0.7"; 25 26 // Default log verbosity: 0 for no messages through 5 (writes everything) 27 int XmlRpcLogHandler::_verbosity = 0; 28 29 // Default log handler 30 static class DefaultLogHandler : public XmlRpcLogHandler { 31 public: 32 33 void log(int level, const char* msg) { 34 #ifdef USE_WINDOWS_DEBUG 35 if (level <= _verbosity) { OutputDebugString(msg); OutputDebugString("\n"); } 36 #else 37 if (level <= _verbosity) std::cout << msg << std::endl; 38 #endif 39 } 40 41 ~DefaultLogHandler() {} 42 } defaultLogHandler; 43 44 // Message log singleton 45 XmlRpcLogHandler* XmlRpcLogHandler::_logHandler = &defaultLogHandler; 46 47 48 // Default error handler 49 static class DefaultErrorHandler : public XmlRpcErrorHandler { 50 public: 51 52 void error(const char* msg) { 53 #ifdef USE_WINDOWS_DEBUG 54 OutputDebugString(msg); OutputDebugString("\n"); 55 #else 56 std::cerr << msg << std::endl; 57 #endif 58 } 59 60 ~DefaultErrorHandler() {} 61 } defaultErrorHandler; 62 63 64 // Error handler singleton 65 XmlRpcErrorHandler* XmlRpcErrorHandler::_errorHandler = &defaultErrorHandler; 66 67 68 // Easy API for log verbosity 69 int XmlRpc::getVerbosity() { return XmlRpcLogHandler::getVerbosity(); } 70 void XmlRpc::setVerbosity(int level) { XmlRpcLogHandler::setVerbosity(level); } 71 72 73 74 void XmlRpcUtil::log(int level, const char* fmt, ...) 75 { 76 if (level <= XmlRpcLogHandler::getVerbosity()) 77 { 78 va_list va; 79 char buf[1024]; 80 va_start( va, fmt); 81 vsnprintf(buf,sizeof(buf)-1,fmt,va); 82 buf[sizeof(buf)-1] = 0; 83 XmlRpcLogHandler::getLogHandler()->log(level, buf); 84 } 85 } 86 87 88 void XmlRpcUtil::error(const char* fmt, ...) 89 { 90 va_list va; 91 va_start(va, fmt); 92 char buf[1024]; 93 vsnprintf(buf,sizeof(buf)-1,fmt,va); 94 buf[sizeof(buf)-1] = 0; 95 XmlRpcErrorHandler::getErrorHandler()->error(buf); 96 } 97 98 99 // Returns contents between <tag> and </tag>, updates offset to char after </tag> 100 std::string 101 XmlRpcUtil::parseTag(const char* tag, std::string const& xml, int* offset) 102 { 103 if (*offset >= int(xml.length())) return std::string(); 104 size_t istart = xml.find(tag, *offset); 105 if (istart == std::string::npos) return std::string(); 106 istart += strlen(tag); 107 std::string etag = "</"; 108 etag += tag + 1; 109 size_t iend = xml.find(etag, istart); 110 if (iend == std::string::npos) return std::string(); 111 112 *offset = int(iend + etag.length()); 113 return xml.substr(istart, iend-istart); 114 } 115 116 117 // Returns true if the tag is found and updates offset to the char after the tag 118 bool 119 XmlRpcUtil::findTag(const char* tag, std::string const& xml, int* offset) 120 { 121 if (*offset >= int(xml.length())) return false; 122 size_t istart = xml.find(tag, *offset); 123 if (istart == std::string::npos) 124 return false; 125 126 *offset = int(istart + strlen(tag)); 127 return true; 128 } 129 130 131 // Returns true if the tag is found at the specified offset (modulo any whitespace) 132 // and updates offset to the char after the tag 133 bool 134 XmlRpcUtil::nextTagIs(const char* tag, std::string const& xml, int* offset) 135 { 136 if (*offset >= int(xml.length())) return false; 137 const char* cp = xml.c_str() + *offset; 138 int nc = 0; 139 while (*cp && isspace(*cp)) { 140 ++cp; 141 ++nc; 142 } 143 144 int len = int(strlen(tag)); 145 if (*cp && (strncmp(cp, tag, len) == 0)) { 146 *offset += nc + len; 147 return true; 148 } 149 return false; 150 } 151 152 // Returns the next tag and updates offset to the char after the tag, or empty string 153 // if the next non-whitespace character is not '<' 154 std::string 155 XmlRpcUtil::getNextTag(std::string const& xml, int* offset) 156 { 157 if (*offset >= int(xml.length())) return std::string(); 158 159 size_t pos = *offset; 160 const char* cp = xml.c_str() + pos; 161 while (*cp && isspace(*cp)) { 162 ++cp; 163 ++pos; 164 } 165 166 if (*cp != '<') return std::string(); 167 168 std::string s; 169 do { 170 s += *cp; 171 ++pos; 172 } while (*cp++ != '>' && *cp != 0); 173 174 *offset = int(pos); 175 return s; 176 } 177 178 179 180 // xml encodings (xml-encoded entities are preceded with '&') 181 static const char AMP = '&'; 182 static const char rawEntity[] = { '<', '>', '&', '\'', '\"', 0 }; 183 static const char* xmlEntity[] = { "lt;", "gt;", "amp;", "apos;", "quot;", 0 }; 184 static const int xmlEntLen[] = { 3, 3, 4, 5, 5 }; 185 186 187 // Replace xml-encoded entities with the raw text equivalents. 188 189 std::string 190 XmlRpcUtil::xmlDecode(const std::string& encoded) 191 { 192 std::string::size_type iAmp = encoded.find(AMP); 193 if (iAmp == std::string::npos) 194 return encoded; 195 196 std::string decoded(encoded, 0, iAmp); 197 std::string::size_type iSize = encoded.size(); 198 decoded.reserve(iSize); 199 200 const char* ens = encoded.c_str(); 201 while (iAmp != iSize) { 202 if (encoded[iAmp] == AMP && iAmp+1 < iSize) { 203 int iEntity; 204 for (iEntity=0; xmlEntity[iEntity] != 0; ++iEntity) 205 //if (encoded.compare(iAmp+1, xmlEntLen[iEntity], xmlEntity[iEntity]) == 0) 206 if (strncmp(ens+iAmp+1, xmlEntity[iEntity], xmlEntLen[iEntity]) == 0) 207 { 208 decoded += rawEntity[iEntity]; 209 iAmp += xmlEntLen[iEntity]+1; 210 break; 211 } 212 if (xmlEntity[iEntity] == 0) // unrecognized sequence 213 decoded += encoded[iAmp++]; 214 215 } else { 216 decoded += encoded[iAmp++]; 217 } 218 } 219 220 return decoded; 221 } 222 223 224 // Replace raw text with xml-encoded entities. 225 226 std::string 227 XmlRpcUtil::xmlEncode(const std::string& raw) 228 { 229 std::string::size_type iRep = raw.find_first_of(rawEntity); 230 if (iRep == std::string::npos) 231 return raw; 232 233 std::string encoded(raw, 0, iRep); 234 std::string::size_type iSize = raw.size(); 235 236 while (iRep != iSize) { 237 int iEntity; 238 for (iEntity=0; rawEntity[iEntity] != 0; ++iEntity) 239 if (raw[iRep] == rawEntity[iEntity]) 240 { 241 encoded += AMP; 242 encoded += xmlEntity[iEntity]; 243 break; 244 } 245 if (rawEntity[iEntity] == 0) 246 encoded += raw[iRep]; 247 ++iRep; 248 } 249 return encoded; 250 } 251 252 253 254