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