Home | History | Annotate | Download | only in src
      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