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