• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
log(int level,const char * msg)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 
~DefaultLogHandler()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 
error(const char * msg)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 
~DefaultErrorHandler()60   ~DefaultErrorHandler() {}
61 } defaultErrorHandler;
62 
63 
64 // Error handler singleton
65 XmlRpcErrorHandler* XmlRpcErrorHandler::_errorHandler = &defaultErrorHandler;
66 
67 
68 // Easy API for log verbosity
getVerbosity()69 int XmlRpc::getVerbosity() { return XmlRpcLogHandler::getVerbosity(); }
setVerbosity(int level)70 void XmlRpc::setVerbosity(int level) { XmlRpcLogHandler::setVerbosity(level); }
71 
72 
73 
log(int level,const char * fmt,...)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 
error(const char * fmt,...)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
parseTag(const char * tag,std::string const & xml,int * offset)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
findTag(const char * tag,std::string const & xml,int * offset)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
nextTagIs(const char * tag,std::string const & xml,int * offset)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
getNextTag(std::string const & xml,int * offset)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
xmlDecode(const std::string & encoded)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
xmlEncode(const std::string & raw)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