Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/drtimcooper/XmlRpc4Win.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDr Tim Cooper <tim@skedgo.com>2016-01-11 05:58:11 +0300
committerDr Tim Cooper <tim@skedgo.com>2016-01-11 05:58:11 +0300
commitf808a50dcd60101e727b3b0647a1517f74cfabe7 (patch)
treef09a7c1640c38ea2e8ec0ef772af87a24c99b87d
parent25e8564c23e061bd4b7092f8b4c04228418f5b11 (diff)
Migrating XmlRpc4Win from SourceForget to github
-rw-r--r--.gitignore4
-rw-r--r--PlainAndFast.vcproj206
-rw-r--r--PlainXmlRpc.cpp1476
-rw-r--r--SampleMain.cpp101
-rw-r--r--SampleMain2.cpp136
-rw-r--r--TimXmlRpc.cpp1749
-rw-r--r--TimXmlRpc.sln26
-rw-r--r--TimXmlRpc.vcproj206
-rw-r--r--TimXmlRpc.vs2005.vcproj206
9 files changed, 4110 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..66951c3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.suo
+*.user
+*.exe
+*.zip
diff --git a/PlainAndFast.vcproj b/PlainAndFast.vcproj
new file mode 100644
index 0000000..7e3cd15
--- /dev/null
+++ b/PlainAndFast.vcproj
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="PlainAndFast"
+ ProjectGUID="{15F136BD-94DC-4E42-93AB-99DBFA3756DE}"
+ RootNamespace="PlainAndFast"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4267,4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wininet.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\PlainXmlRpc.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\SampleMain2.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\timxmlrpc.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/PlainXmlRpc.cpp b/PlainXmlRpc.cpp
new file mode 100644
index 0000000..c3bc962
--- /dev/null
+++ b/PlainXmlRpc.cpp
@@ -0,0 +1,1476 @@
+
+#undef UNICODE
+#define _SECURE_SCL 0 // Disable "checked iterators". STL is too slow otherwise.
+#include <windows.h>
+#include <wininet.h>
+#include <fstream>
+#include "PlainXmlRpc.h"
+
+
+
+
+
+#define not !
+#define or ||
+#define and &&
+extern int L;
+extern void stop();
+
+
+
+//---------------------------------- Misc: -------------------------------
+
+static bool strieq(kstr a, kstr b)
+{
+ return _stricmp(a, b) == 0;
+}
+
+
+static bool strbegins(kstr bigstr, kstr smallstr, bool casesensitive)
+{
+ kstr smalls = smallstr;
+ kstr bigs = bigstr;
+ while (*smalls) {
+ if (casesensitive) {
+ if (*bigs != *smalls)
+ return false;
+ else bigs++, smalls++;
+ }
+ else {
+ if (toupper(*bigs) != toupper(*smalls))
+ return false;
+ else bigs++, smalls++;
+ }
+ }
+ return true;
+}
+
+
+static void assert_failed(kstr filename, int line, kstr condition)
+{
+ printf("Assert failed| %s:%d %s\n", filename, line, condition);
+}
+
+#define assert(c) if (c) ; else assert_failed(__FILE__, __LINE__, #c)
+
+
+
+namespace PlainXML {
+
+/*----------------------------------- Generic functions: ------------------------------------*/
+
+XmlValue::~XmlValue()
+{
+ if (nameIsOwned)
+ free(name);
+ name = NULL;
+}
+
+
+// Map something like: "T2-D&amp;T1" to "T2-D&T1"
+// Returns a 'strdup()' version of the input string.
+static str xmlDecode(kstr s, kstr end)
+{
+ str dest = (char*)malloc(end - s + 1);
+ str d = dest;
+ while (s < end) {
+ if (*s != '&')
+ *d++ = *s++;
+ else if (strbegins(s, "&amp;", true))
+ *d++ = '&', s += 5;
+ else if (strbegins(s, "&quot;", true))
+ *d++ = '\"', s += 6;
+ else if (strbegins(s, "&apos;", true)/*not standard*/ or strbegins(s, "&#039;", true))
+ *d++ = '\'', s += 6;
+ else if (strbegins(s, "&lt;", true))
+ *d++ = '<', s += 4;
+ else if (strbegins(s, "&gt;", true))
+ *d++ = '>', s += 4;
+ else if (strbegins(s, "&#", true)) {
+ s += 2;
+ *d++ = atoi(s+2);
+ while (*s >= '0' and *s <= '9')
+ s++;
+ if (*s == ';')
+ s++;
+ }
+ else
+ *d++ = *s++; // assert(false);
+ }
+ *d = '\0';
+ return dest;
+}
+
+
+// Replace raw text with xml-encoded entities.
+
+static std::string xmlEncode(kstr s)
+{
+ std::ostringstream ostr;
+
+ while (*s) {
+ if (*s == '&')
+ ostr << "&amp;";
+ else if (*s == '<')
+ ostr << "&lt;";
+ else if (*s == '>')
+ ostr << "&gt;";
+ else if (*s == '"')
+ ostr << "&quot;";
+ else if (*s == '\'')
+ ostr << "&apos;";// Would David prefer: "&#039;" ?
+ else if (*s < ' ' or *s >= 127)
+ ostr << "&#" << int((unsigned char)*s) << ';';
+ else ostr << *s;
+ s++;
+ }
+ return ostr.str();
+}
+
+
+static void SkipWhiteSpace(kstr &s)
+{
+ while (*s == ' ' or *s == '\t' or *s == '\n' or *s == '\r')
+ s++;
+}
+
+
+static char* GobbleTag(kstr &s, char dest[128])
+// E.g. given: "< string / >", return "<string/>"
+{
+ *dest = '\0';
+ SkipWhiteSpace(s);
+ if (*s != '<')
+ return dest;
+ str d = dest;
+ *d++ = *s++;
+ SkipWhiteSpace(s);
+ while (*s and *s != '>') {
+ if (*s == ' ' and (d[-1] == '<' or d[-1] == '/' or s[1] == ' ' or s[1] == '/' or s[1] == '>'))
+ s++;
+ else *d++ = *s++;
+ }
+ *d++ = '>';
+ *d = '\0';
+ if (*s == '>')
+ s++;
+ return dest;
+}
+
+
+static void GobbleExpectedTag(kstr &s, kstr etag)
+{
+ char tag[128];
+ GobbleTag(s, tag);
+ if (not strieq(tag, etag))
+ throw XmlException(std::string("Expecting tag: ") + etag);
+}
+
+
+XmlValue* ValueFromXml(kstr &s)
+{ XmlValue *value=NULL;
+ str strdupName=NULL;
+ char tag[128];
+
+ GobbleTag(s, tag+1);
+
+ // Set the name of the object:
+ str name = tag + 2;
+ str nameEnd = strchr(name, '>');
+ if (nameEnd) {
+ if (nameEnd[-1] == '/') {
+ // It's a null element, e.g. 'member' within: <fields><member/></fields>
+ nameEnd[-1] = '\0';
+ value = new XmlString("");
+ value->setNameStdrup(name);
+ return value;
+ }
+ else {
+ *nameEnd = '\0';
+ strdupName = strdup(name);
+ *nameEnd = '>';
+ }
+ }
+
+ // Parse the contents:
+ SkipWhiteSpace(s);
+ if (*s == '<' and s[1] == '/') {
+ // This should be an error: and end tag received when we're expecting a start tag.
+ value = new XmlString("");
+ }
+ else if (*s == '<') {
+ // Parse a structured value as an array. If the caller wants it as a struct,
+ // then he can call 'convertToStruct()' on it.
+ XmlArray *array = new XmlArray;
+ array->fromXml(s);
+ value = array;
+ }
+ else {
+ // Parse an atom, as a string:
+ kstr valueEnd = strchr(s, '<');
+ if (valueEnd == NULL)
+ throw XmlException("The XML file is incomplete.");
+ XmlString *stringValue = new XmlString(xmlDecode(s, valueEnd));
+ s = valueEnd;
+ value = stringValue;
+ }
+ *tag = '<';
+ tag[1] = '/';
+ GobbleExpectedTag(s, tag);
+ value->setNameConst(strdupName);
+ return value;
+}
+
+
+void XmlValue::toXml(std::ostringstream &ostr) const
+{
+ if (this == NULL)
+ return;
+ kstr tag = (name and *name) ? name : "value";
+ ostr << '<' << tag << '>';
+ toXmlInternal(ostr);
+ ostr << "</" << tag << ">\n";
+}
+
+
+static bool SuitableForCDATA(str s)
+{
+ if (strchr(s, '<') and strchr(s, '>'))
+ return true;
+ return false;
+}
+
+
+XmlValue* RpcVal(int i, kstr name) { return new XmlInt(i, name); }
+XmlValue* RpcVal(kstr s, kstr name) { return new XmlString(s, name); }
+XmlValue* RpcVal(std::string s, kstr name) { return new XmlString(s.c_str(), name); }
+XmlValue* RpcVal(double f, kstr name) { return new XmlDouble(f, name); }
+XmlValue* RpcVal(bool b, kstr name) { return new XmlBool(b, name); }
+
+
+
+
+//---------------------------------- XmlArray: -------------------------------
+
+void XmlArray::resize(int n)
+{
+ if (n >= _allocated) {
+ // Optimise growing of the array:
+ int power2 = n - 1;
+ power2 |= power2 >> 1;
+ power2 |= power2 >> 2;
+ power2 |= power2 >> 4;
+ power2 |= power2 >> 8;
+ power2 |= power2 >> 16;
+ power2++;
+
+ // Set the size:
+ A = (XmlValue**)realloc(A, power2 * sizeof(XmlValue));
+ memset(A + _allocated, 0, (power2 - _allocated) * sizeof(XmlValue));
+ _allocated = power2;
+ }
+ _size = n;
+}
+
+
+bool XmlArray::operator==(XmlArray &other)
+{
+ if (_size != other._size)
+ return false;
+ for (int i=0; i < _size; i++) {
+ if (A[i] == NULL or other.A[i] == NULL)
+ return A[i] == other.A[i];
+ if (A[i] != other.A[i])//Doesn't work yet. This is only shallow equality.
+ return false;
+ }
+ return true;
+}
+
+
+XmlArray::XmlArray(XmlArray &other)
+{
+ A = NULL;
+ _size = _allocated = 0;
+ resize(other._size);
+ for (int i=0 ; i < _size; i++) {
+ A[i] = other.A[i];
+ }
+}
+
+
+XmlValue* XmlArray::find(const char *s)
+{
+ for (int i=0; i < _size; i++) {
+ if (strcmp(A[i]->getName(), s) == 0)
+ return A[i];
+ }
+ return NULL;
+}
+
+
+void XmlArray::set(const char *s, XmlValue *value)
+{
+ value->setNameConst(s);
+ for (int i=0; i < _size; i++) {
+ if (strcmp(A[i]->getName(), s) == 0) {
+ delete A[i];
+ A[i] = value;
+ return;
+ }
+ }
+ int i = _size;
+ resize(i+1);
+ A[i] = value;
+}
+
+
+XmlArray::~XmlArray()
+{
+ for (int i=0; i < _size; i++) {
+ if (A[i])
+ delete A[i];
+ }
+ free(A);
+}
+
+
+void XmlArray::fromXml(kstr &s)
+{
+ do {
+ SkipWhiteSpace(s);
+ if (strbegins(s, "</", true))
+ break;
+ int n = _size;
+ resize(n+1);
+ A[n] = ValueFromXml(s);
+ } while (true);
+}
+
+
+void XmlArray::toXmlInternal(std::ostringstream &ostr) const
+{
+ for (int i=0; i < _size; ++i) {
+ if (A[i])
+ A[i]->toXml(ostr);
+ }
+}
+
+
+
+
+//---------------------------------- base64.h: -------------------------------
+ /* <Chris Morley> */
+static
+int _base64Chars[]= {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
+ 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
+ '0','1','2','3','4','5','6','7','8','9',
+ '+','/' };
+
+
+#define _0000_0011 0x03
+#define _1111_1100 0xFC
+#define _1111_0000 0xF0
+#define _0011_0000 0x30
+#define _0011_1100 0x3C
+#define _0000_1111 0x0F
+#define _1100_0000 0xC0
+#define _0011_1111 0x3F
+
+#define _EQUAL_CHAR (-1)
+#define _UNKNOWN_CHAR (-2)
+
+#define _IOS_FAILBIT std::ios_base::failbit
+#define _IOS_EOFBIT std::ios_base::eofbit
+#define _IOS_BADBIT std::ios_base::badbit
+#define _IOS_GOODBIT std::ios_base::goodbit
+
+// TEMPLATE CLASS base64_put
+class base64 {
+public:
+
+ typedef unsigned char byte_t;
+ typedef char char_type;
+ typedef std::char_traits<char> traits_type;
+
+ // base64 requires max line length <= 72 characters
+ // you can fill end of line
+ // it may be crlf, crlfsp, noline or other class like it
+
+
+ struct crlf
+ {
+ template<class _OI>
+ _OI operator()(_OI _To) const{
+ *_To = std::char_traits<char>::to_char_type('\r'); ++_To;
+ *_To = std::char_traits<char>::to_char_type('\n'); ++_To;
+
+ return (_To);
+ }
+ };
+
+
+ struct crlfsp
+ {
+ template<class _OI>
+ _OI operator()(_OI _To) const{
+ *_To = std::char_traits<char>::to_char_type('\r'); ++_To;
+ *_To = std::char_traits<char>::to_char_type('\n'); ++_To;
+ *_To = std::char_traits<char>::to_char_type(' '); ++_To;
+
+ return (_To);
+ }
+ };
+
+ struct noline
+ {
+ template<class _OI>
+ _OI operator()(_OI _To) const{
+ return (_To);
+ }
+ };
+
+ struct three2four
+ {
+ void zero()
+ {
+ _data[0] = 0;
+ _data[1] = 0;
+ _data[2] = 0;
+ }
+
+ byte_t get_0() const
+ {
+ return _data[0];
+ }
+ byte_t get_1() const
+ {
+ return _data[1];
+ }
+ byte_t get_2() const
+ {
+ return _data[2];
+ }
+
+ void set_0(byte_t _ch)
+ {
+ _data[0] = _ch;
+ }
+
+ void set_1(byte_t _ch)
+ {
+ _data[1] = _ch;
+ }
+
+ void set_2(byte_t _ch)
+ {
+ _data[2] = _ch;
+ }
+
+ // 0000 0000 1111 1111 2222 2222
+ // xxxx xxxx xxxx xxxx xxxx xxxx
+ // 0000 0011 1111 2222 2233 3333
+
+ int b64_0() const {return (_data[0] & _1111_1100) >> 2;}
+ int b64_1() const {return ((_data[0] & _0000_0011) << 4) + ((_data[1] & _1111_0000)>>4);}
+ int b64_2() const {return ((_data[1] & _0000_1111) << 2) + ((_data[2] & _1100_0000)>>6);}
+ int b64_3() const {return (_data[2] & _0011_1111);}
+
+ void b64_0(int _ch) {_data[0] = ((_ch & _0011_1111) << 2) | (_0000_0011 & _data[0]);}
+
+ void b64_1(int _ch) {
+ _data[0] = ((_ch & _0011_0000) >> 4) | (_1111_1100 & _data[0]);
+ _data[1] = ((_ch & _0000_1111) << 4) | (_0000_1111 & _data[1]); }
+
+ void b64_2(int _ch) {
+ _data[1] = ((_ch & _0011_1100) >> 2) | (_1111_0000 & _data[1]);
+ _data[2] = ((_ch & _0000_0011) << 6) | (_0011_1111 & _data[2]); }
+
+ void b64_3(int _ch){
+ _data[2] = (_ch & _0011_1111) | (_1100_0000 & _data[2]);}
+
+ private:
+ byte_t _data[3];
+
+ };
+
+
+
+
+ template<class _II, class _OI, class _State, class _Endline>
+ _II put(_II _First, _II _Last, _OI _To, _State& _St, _Endline _Endl) const
+ {
+ three2four _3to4;
+ int line_octets = 0;
+
+ while(_First != _Last)
+ {
+ _3to4.zero();
+
+ //
+ _3to4.set_0(*_First);
+ _First++;
+
+ if(_First == _Last)
+ {
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type('='); ++_To;
+ *_To = std::char_traits<char>::to_char_type('='); ++_To;
+ goto __end;
+ }
+
+ _3to4.set_1(*_First);
+ _First++;
+
+ if(_First == _Last)
+ {
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_2()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type('='); ++_To;
+ goto __end;
+ }
+
+ _3to4.set_2(*_First);
+ _First++;
+
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_2()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_3()]); ++_To;
+
+ if(line_octets == 17) // base64
+ {
+ //_To = _Endl(_To);
+ *_To = '\n'; ++_To;
+ line_octets = 0;
+ }
+ else
+ ++line_octets;
+ }
+
+ __end: ;
+
+ return (_First);
+
+ }
+
+
+ template<class _II, class _OI, class _State>
+ _II get(_II _First, _II _Last, _OI _To, _State& _St) const
+ {
+ three2four _3to4;
+ int _Char;
+
+ while(_First != _Last)
+ {
+
+ // Take octet
+ _3to4.zero();
+
+ // -- 0 --
+ // Search next valid char...
+ while((_Char = _getCharType(*_First)) < 0 && _Char == _UNKNOWN_CHAR)
+ {
+ if(++_First == _Last)
+ {
+ _St |= _IOS_FAILBIT|_IOS_EOFBIT; return _First; // unexpected EOF
+ }
+ }
+
+ if(_Char == _EQUAL_CHAR){
+ // Error! First character in octet can't be '='
+ _St |= _IOS_FAILBIT;
+ return _First;
+ }
+ else
+ _3to4.b64_0(_Char);
+
+
+ // -- 1 --
+ // Search next valid char...
+ while(++_First != _Last)
+ if((_Char = _getCharType(*_First)) != _UNKNOWN_CHAR)
+ break;
+
+ if(_First == _Last) {
+ _St |= _IOS_FAILBIT|_IOS_EOFBIT; // unexpected EOF
+ return _First;
+ }
+
+ if(_Char == _EQUAL_CHAR){
+ // Error! Second character in octet can't be '='
+ _St |= _IOS_FAILBIT;
+ return _First;
+ }
+ else
+ _3to4.b64_1(_Char);
+
+
+ // -- 2 --
+ // Search next valid char...
+ while(++_First != _Last)
+ if((_Char = _getCharType(*_First)) != _UNKNOWN_CHAR)
+ break;
+
+ if(_First == _Last) {
+ // Error! Unexpected EOF. Must be '=' or base64 character
+ _St |= _IOS_FAILBIT|_IOS_EOFBIT;
+ return _First;
+ }
+
+ if(_Char == _EQUAL_CHAR){
+ // OK!
+ _3to4.b64_2(0);
+ _3to4.b64_3(0);
+
+ // chek for EOF
+ if(++_First == _Last)
+ {
+ // Error! Unexpected EOF. Must be '='. Ignore it.
+ //_St |= _IOS_BADBIT|_IOS_EOFBIT;
+ _St |= _IOS_EOFBIT;
+ }
+ else
+ if(_getCharType(*_First) != _EQUAL_CHAR)
+ {
+ // Error! Must be '='. Ignore it.
+ //_St |= _IOS_BADBIT;
+ }
+ else
+ ++_First; // Skip '='
+
+ // write 1 byte to output
+ *_To = (byte_t) _3to4.get_0();
+ return _First;
+ }
+ else
+ _3to4.b64_2(_Char);
+
+
+ // -- 3 --
+ // Search next valid char...
+ while(++_First != _Last)
+ if((_Char = _getCharType(*_First)) != _UNKNOWN_CHAR)
+ break;
+
+ if(_First == _Last) {
+ // Unexpected EOF. It's error. But ignore it.
+ //_St |= _IOS_FAILBIT|_IOS_EOFBIT;
+ _St |= _IOS_EOFBIT;
+
+ return _First;
+ }
+
+ if(_Char == _EQUAL_CHAR)
+ {
+ // OK!
+ _3to4.b64_3(0);
+
+ // write to output 2 bytes
+ *_To = (byte_t) _3to4.get_0();
+ *_To = (byte_t) _3to4.get_1();
+
+ ++_First; // set position to next character
+
+ return _First;
+ }
+ else
+ _3to4.b64_3(_Char);
+
+
+ // write to output 3 bytes
+ *_To = (byte_t) _3to4.get_0();
+ *_To = (byte_t) _3to4.get_1();
+ *_To = (byte_t) _3to4.get_2();
+
+ ++_First;
+
+
+ } // while(_First != _Last)
+
+ return (_First);
+ }
+
+protected:
+
+ int _getCharType(int _Ch) const
+ {
+ if(_base64Chars[62] == _Ch)
+ return 62;
+
+ if(_base64Chars[63] == _Ch)
+ return 63;
+
+ if((_base64Chars[0] <= _Ch) && (_base64Chars[25] >= _Ch))
+ return _Ch - _base64Chars[0];
+
+ if((_base64Chars[26] <= _Ch) && (_base64Chars[51] >= _Ch))
+ return _Ch - _base64Chars[26] + 26;
+
+ if((_base64Chars[52] <= _Ch) && (_base64Chars[61] >= _Ch))
+ return _Ch - _base64Chars[52] + 52;
+
+ if(_Ch == std::char_traits<char>::to_int_type('='))
+ return _EQUAL_CHAR;
+
+ return _UNKNOWN_CHAR;
+ }
+};
+
+
+void XmlBinary::fromXml(kstr &s)
+{
+ kstr valueEnd = strchr(s, '<');
+ if (valueEnd == NULL)
+ throw XmlException("Bad base64");
+
+ data = new BinaryData();
+ // check whether base64 encodings can contain chars xml encodes...
+
+ // convert from base64 to binary
+ int iostatus = 0;
+ base64 decoder;
+ std::back_insert_iterator<BinaryData> ins = std::back_inserter(*data);
+ decoder.get(s, valueEnd, ins, iostatus);
+
+ s = valueEnd;
+}
+
+
+void XmlBinary::toXmlInternal(std::ostringstream &ostr) const
+{
+ // convert to base64
+ std::vector<char> base64data;
+ int iostatus = 0;
+ base64 encoder;
+ std::back_insert_iterator<std::vector<char> > ins = std::back_inserter(base64data);
+ encoder.put(data->begin(), data->end(), ins, iostatus, base64::crlf());
+
+ // Wrap with xml
+ ostr.write(&base64data[0], base64data.size());
+}
+
+
+
+
+//---------------------- Primitive Types: ---------------------
+
+void XmlBool::fromXml(kstr &s)
+{
+ if (*s == '0' and s[1] == '<') {
+ b = false;
+ s++;
+ }
+ else if (*s == '1' and s[1] == '<') {
+ b = true;
+ s++;
+ }
+ else throw XmlException("bad BOOL");
+}
+
+
+void XmlBool::toXmlInternal(std::ostringstream &ostr) const
+{
+ ostr << (b?"1":"0");
+}
+
+
+void XmlInt::fromXml(kstr &s)
+{
+ char* valueEnd;
+ long ivalue = strtol(s, &valueEnd, 10);
+ if (valueEnd == s)
+ throw XmlException("Bad int");
+ i = int(ivalue);
+ s = valueEnd;
+}
+
+
+void XmlInt::toXmlInternal(std::ostringstream &ostr) const
+{
+ ostr << i;
+}
+
+
+void XmlDouble::fromXml(kstr &s)
+{
+ char* valueEnd;
+ f = strtod(s, &valueEnd);
+ if (valueEnd == s)
+ throw XmlException("Bad double");
+ s = valueEnd;
+}
+
+
+void XmlDouble::toXmlInternal(std::ostringstream &ostr) const
+{
+ ostr << f;
+ // This will use the default ostream::precision() to display the double. To display
+ // values with greater accuracy, call e.g. 'ostr.precision(12)' at the top level.
+}
+
+
+void XmlString::fromXml(kstr &s)
+{
+ kstr valueEnd = strchr(s, '<');
+ if (valueEnd == NULL)
+ throw XmlException("Bad string");
+ stri = xmlDecode(s, valueEnd);
+ s = valueEnd;
+}
+
+
+void XmlString::toXmlInternal(std::ostringstream &ostr) const
+{
+ if (stri == NULL or *stri == '\0')
+ ;
+ else if (strstr(stri, "]]>"))
+ ostr << "CDATA elements not allowed";
+ else if (SuitableForCDATA(stri))
+ ostr << "\n<![CDATA[" << stri << "]]>\n";
+ else ostr << xmlEncode(stri);
+}
+
+
+void XmlDateTime::fromXml(const char* &s)
+{
+ const char* valueEnd = strchr(s, '<');
+ if (valueEnd == NULL)
+ throw XmlException("Bad time value");
+ if (sscanf_s(s, "%4d%2d%2dT%2d:%2d:%2d", &data.tm_year,&data.tm_mon,&data.tm_mday,&data.tm_hour,&data.tm_min,&data.tm_sec) != 6)
+ throw XmlException("Bad time value");
+ data.tm_isdst = 0;
+ data.tm_year -= 1900;
+ data.tm_mon -= 1;
+ s = valueEnd;
+}
+
+
+void XmlString::asTmStruct(struct tm *data)
+{
+ if (sscanf_s(stri, "%4d%2d%2dT%2d:%2d:%2d", &data->tm_year,&data->tm_mon,&data->tm_mday,&data->tm_hour,&data->tm_min,&data->tm_sec) != 6)
+ throw XmlException("Bad time value");
+ data->tm_isdst = 0;
+ data->tm_mon -= 1;
+ data->tm_year -= 1900;
+ data->tm_wday = data->tm_yday = 0;
+}
+
+
+void XmlDateTime::toXmlInternal(std::ostringstream &ostr) const
+{
+ char buf[30];
+ _snprintf_s(buf, sizeof(buf), sizeof(buf)-1,
+ "%4d%02d%02dT%02d:%02d:%02d",
+ data.tm_year+1900,data.tm_mon+1,data.tm_mday,data.tm_hour,data.tm_min,data.tm_sec);
+ ostr << buf;
+}
+
+
+
+//------------------------ RPC calls: -------------------
+
+XmlValue* parseMethodResponse(kstr s)
+{ char xmlVersion[128];
+
+ GobbleTag(s, xmlVersion);
+ if (! strbegins(xmlVersion, "<?xml version", false))
+ throw XmlException(std::string(s));
+ while (strchr(" \n\r\t", *s))
+ s++;
+ if (*s != '<')
+ throw XmlException(std::string(s)); // Typically: "java.lang.NullPointerException" + stack-trace
+ return ValueFromXml(s);
+}
+
+
+void buildCall(kstr method, XmlArray *args, std::ostringstream &ostr)
+{
+ ostr << "<?xml version=\"1.0\"?>\r\n";
+ ostr << '<' << method << ">\n";
+ args->toXml(ostr);
+ ostr << "</" << method << ">\n";
+}
+
+
+
+
+/*-------------------------- class XmlClient: ----------------------*/
+
+class XmlImplementation {
+ XmlClient::protocol_enum protocol;
+ bool ignoreCertificateAuthority;
+ HINTERNET hInternet;
+ HINTERNET hConnect;
+ std::string object;
+ DWORD HttpErrcode;
+ FILE *debugFile;
+ int port;
+
+ void hadError(str function);
+ bool connect(const char* server);
+
+public:
+ struct BasicAuth_node {
+ getBasicAuth_UsernameAndPassword_fn FindUsernameAndPassword;
+ char username[256];
+ char password[256];
+
+ BasicAuth_node() {
+ FindUsernameAndPassword = NULL;
+ username[0] = '\0';
+ password[0] = '\0';
+ }
+ } BasicAuth;
+ XmlCallback Callback;
+ void *context;
+ int totalBytes;
+ std::string errmsg;
+ bool isFault;
+
+ XmlImplementation(const char* server, int port, const char* object, XmlClient::protocol_enum protocol);
+ XmlImplementation(const char* URI, FILE *debugFile);
+ XmlValue* execute(const char* method, XmlArray *params);
+ void setCallback(XmlCallback Callback, void* context)
+ { this->Callback = Callback; this->context = context; }
+ void setIgnoreCertificateAuthority(bool value) { ignoreCertificateAuthority = value; }
+ void setDebugFile(FILE *_debugFile) { debugFile = _debugFile; }
+ ~XmlImplementation();
+};
+
+
+XmlClient::XmlClient(const char* server, int port, const char* object, protocol_enum protocol)
+{
+ secret = new XmlImplementation(server, port, object, protocol);
+}
+
+
+XmlClient::XmlClient(const char* URI, FILE *debugFile)
+{
+ secret = new XmlImplementation(URI, debugFile);
+}
+
+
+XmlValue* XmlClient::execute(const char* method, XmlArray *params)
+{
+ return secret->execute(method, params);
+}
+
+
+std::string XmlClient::getError()
+{
+ if (secret->errmsg.size() > 1254)
+ secret->errmsg.resize(1254);
+ return secret->errmsg;
+}
+
+
+void XmlClient::setError(std::string msg)
+{
+ secret->errmsg = msg;
+}
+
+
+void XmlClient::setCallback(XmlCallback Callback, void* context)
+{
+ secret->setCallback(Callback, context);
+}
+
+
+void XmlClient::setBasicAuth_Callback(getBasicAuth_UsernameAndPassword_fn fn)
+{
+ secret->BasicAuth.FindUsernameAndPassword = fn;
+}
+
+
+void XmlClient::setBasicAuth_UsernameAndPassword(const char* username, const char* password)
+{
+ strcpy(secret->BasicAuth.username, username);
+ strcpy(secret->BasicAuth.password, password);
+}
+
+
+void XmlClient::setIgnoreCertificateAuthority(bool value)
+{
+ secret->setIgnoreCertificateAuthority(value);
+}
+
+
+void XmlClient::setDebugFile(FILE *debugFile)
+{
+ secret->setDebugFile(debugFile);
+}
+
+
+bool XmlClient::isFault() const
+{
+ return secret->isFault;
+}
+
+
+void XmlClient::close()
+{
+ delete secret;
+ secret = NULL;
+}
+
+
+XmlImplementation::XmlImplementation(const char* server, int _port, const char* _object,
+ XmlClient::protocol_enum _protocol)
+{
+ port = _port;
+ object = _object;
+ if (_protocol == XmlClient::XMLRPC_AUTO)
+ protocol = (port == 80) ? XmlClient::XMLRPC_HTTP :
+ (port == 443) ? XmlClient::XMLRPC_HTTPS : XmlClient::XMLRPC_HTTP;
+ else protocol = _protocol;
+ ignoreCertificateAuthority = false;
+ hConnect = NULL;
+ debugFile = NULL;
+ connect(server);
+}
+
+
+XmlImplementation::XmlImplementation(const char* URI, FILE* debugFile)
+{
+ port = 0;
+ ignoreCertificateAuthority = false;
+ if (strbegins(URI, "https://", false)) {
+ protocol = XmlClient::XMLRPC_HTTPS;
+ URI += 8;
+ port = 443;
+ }
+ else if (strbegins(URI, "http://", false)) {
+ protocol = XmlClient::XMLRPC_HTTP;
+ URI += 7;
+ port = 80;
+ }
+ else {
+ errmsg = "The URI must begin with \"https://\" or \"http://\".";
+ return;
+ }
+ kstr t = URI;
+ while (*t != ':' and *t != '\0' and *t != '/')
+ t++;
+ std::string server(URI, t - URI);
+ if (*t == ':') {
+ t++;
+ port = atoi(t);
+ while (*t >= '0' and *t <= '9')
+ t++;
+ }
+ object = t; // should start with '/'.
+ this->debugFile = debugFile;
+ connect(server.c_str());
+}
+
+
+bool XmlImplementation::connect(const char* server)
+{
+ Callback = NULL;
+ context = NULL;
+ totalBytes = 0;
+ hInternet = InternetOpen("Xml", 0, NULL, NULL, 0);
+ if (hInternet == NULL) {
+ hadError("InternetOpen");
+ return false;
+ }
+ if (debugFile) {
+ fprintf(debugFile, "Attempting to connect to server: %s port: %d\n", server, port);
+ fflush(debugFile);
+ }
+ hConnect = InternetConnect(hInternet, server, port,
+ NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)this);
+ if (hConnect == NULL) {
+ hadError("InternetConnect");
+ return false;
+ }
+ DWORD dwTimeout=999000; // 999 seconds
+ InternetSetOption(hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout, sizeof(DWORD));
+ InternetSetOption(hConnect, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout, sizeof(DWORD));
+ if (debugFile) {
+ fputs("Got a handle\n", debugFile);
+ fflush(debugFile);
+ }
+ return true;
+}
+
+
+// Converts a GetLastError() code into a human-readable string.
+void XmlImplementation::hadError(str function)
+{
+ errmsg = function;
+ errmsg += " : ";
+
+ int LastError = GetLastError();
+ if (LastError == ERROR_INTERNET_TIMEOUT)
+ errmsg += "Internet timeout";
+ else if (LastError == ERROR_INTERNET_INVALID_CA)
+ errmsg += "Invalid certificate authority";
+ else if (LastError == ERROR_INTERNET_SECURITY_CHANNEL_ERROR)
+ errmsg += "Talking HTTPS to an HTTP server?";
+ else if (LastError == ERROR_INTERNET_CANNOT_CONNECT)
+ errmsg += "Failed to connect";
+ else if (LastError == ERROR_INTERNET_NAME_NOT_RESOLVED)
+ errmsg += "Name not resolved";
+ else if (LastError == ERROR_INTERNET_INVALID_URL)
+ errmsg += "Invalid URL";
+ else if (LastError == ERROR_INTERNET_NAME_NOT_RESOLVED)
+ errmsg += "Domain name not resolved";
+ else if (LastError == ERROR_INTERNET_CONNECTION_RESET)
+ errmsg += "Connection reset";
+ else if (LastError == ERROR_INTERNET_NOT_INITIALIZED)
+ errmsg += "Internet not initialised";
+ else if (LastError == ERROR_INTERNET_CONNECTION_ABORTED)
+ errmsg += "Connection aborted";
+ else {
+ static str buf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ LastError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (str)&buf,
+ 0,
+ NULL
+ );
+ if (buf == NULL) {
+ char tmp[512];
+ sprintf(tmp, "Error %d", LastError);
+ errmsg += tmp;
+ }
+ else {
+ errmsg += buf;
+ LocalFree(buf);
+ }
+ }
+ if (debugFile) {
+ fprintf(debugFile, "Error: %s\n", errmsg.c_str());
+ fflush(debugFile);
+ }
+}
+
+
+static void CALLBACK myInternetCallback(HINTERNET hInternet,
+ DWORD_PTR dwContext,
+ DWORD dwInternetStatus,
+ LPVOID lpvStatusInformation,
+ DWORD dwStatusInformationLength)
+{
+ XmlImplementation *connection = (XmlImplementation*)dwContext;
+ if (connection and connection->Callback) {
+ static char buf[512];
+ str status;
+ switch (dwInternetStatus) {
+ case INTERNET_STATUS_RECEIVING_RESPONSE: if (connection->totalBytes == 0)
+ status = "Waiting for response";
+ else status = "Receiving response";
+ break;
+ case INTERNET_STATUS_RESPONSE_RECEIVED: status = "Response received"; break;
+ case INTERNET_STATUS_HANDLE_CLOSING: status = "Handle closing"; break;
+ case INTERNET_STATUS_REQUEST_SENT: status = "Data sent"; break;
+ case INTERNET_STATUS_SENDING_REQUEST: status = "Sending data"; break;
+ default: status = buf;
+ sprintf(buf, "Status %d", dwInternetStatus);
+ break;
+ }
+ connection->Callback(connection->context, status);
+ }
+}
+
+
+XmlValue* XmlImplementation::execute(const char* method, XmlArray *params)
+{
+ errmsg = "";
+
+ if (hConnect == NULL) {
+ errmsg = "No connection";
+ return false;
+ }
+
+ // Build the request as an XML file:
+ std::ostringstream ostr;
+ buildCall(method, params, ostr);
+
+ // Create the HttpOpenRequest object:
+ if (debugFile) {
+ fputs("Sending data\n", debugFile);
+ fflush(debugFile);
+ }
+ if (Callback)
+ Callback(context, "Sending data");
+ const char* acceptTypes[2] = { "text/*", NULL };
+ int flags = INTERNET_FLAG_DONT_CACHE;
+ flags |= INTERNET_FLAG_KEEP_CONNECTION;
+ if (protocol != XmlClient::XMLRPC_HTTP)
+ flags |= INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
+RETRY:
+ HINTERNET hHttpFile = HttpOpenRequest(
+ hConnect,
+ "POST",
+ object.c_str(),
+ HTTP_VERSION,
+ NULL,
+ acceptTypes,
+ flags,
+ (DWORD_PTR)this);
+ if (hHttpFile == NULL) {
+ hadError("HttpOpenRequest");
+ return false;
+ }
+ if (debugFile) {
+ fputs("HttpOpenRequest() succeeded\n", debugFile);
+ fflush(debugFile);
+ }
+ InternetSetStatusCallback(hHttpFile, myInternetCallback);
+
+ if (ignoreCertificateAuthority) {
+ DWORD dwFlags;
+ DWORD dwBuffLen = sizeof(dwFlags);
+
+ InternetQueryOption(hHttpFile, INTERNET_OPTION_SECURITY_FLAGS,
+ (LPVOID)&dwFlags, &dwBuffLen);
+ dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
+ InternetSetOption(hHttpFile, INTERNET_OPTION_SECURITY_FLAGS,
+ &dwFlags, sizeof (dwFlags) );
+ }
+
+ // Add the 'Content-Type' and 'Content-length' headers
+ char header[255]; // Thanks, Anthony Chan.
+ sprintf(header, "Content-Type: text/xml\r\nContent-length: %d", ostr.str().size());
+ HttpAddRequestHeaders(hHttpFile, header, strlen(header), HTTP_ADDREQ_FLAG_ADD);
+
+ // Add authentication fields:
+ //InternetSetOption(hHttpFile, ???INTERNET_OPTION_SECURITY_FLAGS,
+ // &dwFlags, ??sizeof (dwFlags) );
+
+ //
+ std::string text = ostr.str();
+
+ // Debug output:
+ if (debugFile) {
+ fputs(text.c_str(), debugFile);
+ fflush(debugFile);
+ }
+
+ // Send the request:
+ if (! HttpSendRequest(hHttpFile, NULL, 0, (LPVOID)text.c_str(), text.size())) {
+ hadError("HttpSendRequest");
+ return false;
+ }
+ if (Callback)
+ Callback(context, "Data sent...");
+ if (debugFile) {
+ fputs("Waiting for response\n", debugFile);
+ fflush(debugFile);
+ }
+
+ // Read the response:
+ char* buf = NULL;
+ int len = 0;
+ do {
+ DWORD bytesAvailable;
+ if (!InternetQueryDataAvailable(hHttpFile, &bytesAvailable, 0, (DWORD_PTR)this)) {
+ hadError("InternetQueryDataAvailable");
+ break;
+ }
+ if (bytesAvailable == 0)
+ break; // This is the EOF condition.
+
+ buf = (char*)realloc(buf, len+bytesAvailable+1);
+
+ // Read the data from the HINTERNET handle.
+ DWORD bytesRead;
+ if (!InternetReadFile(hHttpFile,
+ (LPVOID)(buf + len),
+ bytesAvailable,
+ &bytesRead))
+ {
+ hadError("InternetReadFile");
+ break;
+ }
+
+ len += bytesRead;
+ buf[len] = '\0';
+ totalBytes = len;
+
+ } while (true);
+
+ //
+ if (debugFile) {
+ fputs("Got response\n", debugFile);
+ fputs(buf, debugFile);
+ fflush(debugFile);
+ }
+
+ // Roel Vanhout's insertion: Did we get a HTTP_STATUS_OK response? If not, why not?
+ // XMLRPC spec says always return 200 for a valid answer. So if it's anything other than
+ // 200, it's an error (i.e., no support for redirects etc.).
+ DWORD buf_size, dummy;
+ buf_size = sizeof(DWORD);
+ if (!HttpQueryInfo(hHttpFile, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &HttpErrcode, &buf_size, 0)) {
+ errmsg = "Could not query HTTP result status";
+ if (debugFile) {
+ fputs("Could not query HTTP result status\n", debugFile);
+ fflush(debugFile);
+ }
+ free(buf);
+ return false;
+ }
+ if (HttpErrcode == HTTP_STATUS_OK) {
+ // good.
+ }
+ else if (HttpErrcode == HTTP_STATUS_DENIED or HttpErrcode == HTTP_STATUS_PROXY_AUTH_REQ) {
+ if (BasicAuth.FindUsernameAndPassword) {
+ free(buf);
+ buf = NULL;
+ if (BasicAuth.FindUsernameAndPassword(BasicAuth.username[0] != '\0', BasicAuth.username, BasicAuth.password))
+ goto RETRY;
+ }
+ errmsg = "HTTP Basic authentication failed. You need to provide a username and password.";
+ goto ABORT;
+ }
+ else {
+ buf_size = 0;
+ HttpQueryInfo(hHttpFile, HTTP_QUERY_STATUS_TEXT, &dummy, &buf_size, 0);
+ buf_size++; // For the '\0'
+ char* status_text = (char*)::malloc(buf_size);
+ if (! HttpQueryInfo(hHttpFile, HTTP_QUERY_STATUS_TEXT, status_text, &buf_size, 0))
+ errmsg = "Could not query HTTP result status";
+ else {
+ char buf[512];
+ sprintf(buf, "Low level (HTTP) error: %d %s", HttpErrcode, status_text);
+ errmsg = buf;
+ }
+ if (debugFile) {
+ fprintf(debugFile, "Got status=%d\n%s\n", HttpErrcode, errmsg.c_str());
+ fflush(debugFile);
+ }
+ABORT:
+ InternetCloseHandle(hHttpFile);
+ free(buf);
+ return false;
+ }
+
+ // Close the HttpRequest object:
+ InternetCloseHandle(hHttpFile);
+
+ // Parse the response:
+ if (len == 0) {
+ free(buf); // 'buf' will always be NULL unless for some strange reason,
+ // InternetReadFile() returns 'false' on the first pass.
+ errmsg = "The server responded with an empty message.";
+ return false;
+ }
+
+ XmlValue *result = NULL;
+ try {
+ result = parseMethodResponse(buf);
+ }
+ catch (XmlException err) {
+ errmsg = err.getMessage();
+ }
+ free(buf);
+
+ // Finished:
+ return result;
+}
+
+
+XmlImplementation::~XmlImplementation()
+{
+ if (hConnect)
+ InternetCloseHandle(hConnect);
+ if (hInternet)
+ InternetCloseHandle(hInternet);
+}
+
+
+}; // namespace PlainXML
+
+
+
+//---------------------------- Unit testing: ----------------------
+
+#if 0
+using PlainXML::XmlValue;
+
+
+static void RoundTrip(XmlValue *a)
+{
+ std::ostringstream ostr;
+ a->toXml(ostr);
+ std::string buf = ostr.str();
+ XmlBool *b = ValueFromXml(buf.c_str());
+ //assert(a == b);
+}
+
+
+void XmlUnitTest()
+{
+ try {
+ XmlValue result;
+ char buf[327680];
+ std::ifstream input("C:\\Documents and Settings\\edval\\Desktop\\Edval data\\debug.txt");
+ input.read(buf, sizeof(buf));
+ kstr s = buf;
+ result.fromXml(s);
+ for (int i=0; i < result.size(); i++) {
+ XmlValue el = result[i];
+ std::string _AcademicYear = el["ACADEMIC_YEAR"];
+ int AcademicYearId = el["ACADEMIC_YEAR_ID"];
+ }
+ } catch (PlainXML::XmlException e) {
+ }
+
+ std::vector<XmlValue> V;
+ V.push_back(10);
+ V.push_back(20);
+ V.push_back(30);
+ V.push_back(40);
+ V.push_back(50);
+
+ XmlValue a = "Hello you";
+ RoundTrip(a);
+
+ XmlValue harry;
+ harry[0] = 56;
+ harry[1] = 560;
+ harry[2] = 115;
+ harry[3] = 145;
+ harry[4] = 35;
+
+ //5
+ XmlValue binny((void*)XmlUnitTest, 30);
+ RoundTrip(binny);
+
+ XmlValue jenny;
+ jenny["NAME"] = "Electric boots";
+ jenny["code"] = "54121";
+ jenny["status"] = true;
+
+ //14
+ a.clear();
+ a["CHARGE"] = 505;
+ a["SPIN"] = "foo";
+ a["COLOUR"] = false;
+ a["BENNY"] = harry;
+ a["BINNY"] = binny;
+ a["JENNY"] = jenny;
+ a["EMPTY"] = "";
+ RoundTrip(a);
+
+ // Copy constructors:
+ XmlValue b;
+ {
+ XmlValue copy = a;
+ XmlValue tmp = copy;
+ b = tmp;
+ }
+ assert(a == b);
+}
+
+#endif
diff --git a/SampleMain.cpp b/SampleMain.cpp
new file mode 100644
index 0000000..afbe65c
--- /dev/null
+++ b/SampleMain.cpp
@@ -0,0 +1,101 @@
+#include <iostream>
+#include "TimXmlRpc.h"
+
+
+// main.cpp: includes both a little unit test and a sample client program.
+
+
+static void BasicTest()
+{
+ // Replace this URL with your own URL:
+ XmlRpcClient Connection("http://web.edval.com.au/rpc");
+ Connection.setIgnoreCertificateAuthority();
+ //Connection.setBasicAuth_Callback(PopUpAPrettyDialog);
+ Connection.setBasicAuth_UsernameAndPassword("foo", "goo");
+
+ // Call: arumate.getKilowatts(string, integer) :
+ XmlRpcValue args, result;
+ args[0] = "test";
+ args[1] = 1;
+
+ //
+ double g = 3.14159;
+ XmlRpcValue binary(&g, sizeof(g));
+ args[2] = binary;
+ XmlRpcValue::BinaryData bdata = binary;
+
+ // Replace this function name with your own:
+ if (! Connection.execute("getKilowatts", args, result)) {
+ std::cout << Connection.getError();
+ }
+ else if (result.getType() == XmlRpcValue::TypeString)
+ std::cout << result.GetStdString();
+ else std::cout << "Success\n";
+}
+
+
+static void AdvancedTest()
+{
+ XmlRpcValue args, result;
+
+ // Passing datums:
+ args[0] = "a string";
+ args[1] = 1;
+ args[2] = true;
+ args[3] = 3.14159;
+ struct tm timeNow;
+ args[4] = XmlRpcValue(&timeNow);
+
+ // Passing an array:
+ XmlRpcValue array;
+ array[0] = 4;
+ array[1] = 5;
+ array[2] = 6;
+ args[5] = array;
+ // Note: if there's a chance that the array contains zero elements,
+ // you'll need to call:
+ // array.initAsArray();
+ // ...because otherwise the type will never get set to "TypeArray" and
+ // the value will be a "TypeInvalid".
+
+ // Passing a struct:
+ XmlRpcValue record;
+ record["SOURCE"] = "a";
+ record["DESTINATION"] = "b";
+ record["LENGTH"] = 5;
+ args[6] = record;
+ // We don't support zero-size struct's...Surely no-one needs these?
+
+ // Make the call:
+ XmlRpcClient Connection("https://61.95.191.232:9600/arumate/rpc/xmlRpcServer.php");
+ Connection.setIgnoreCertificateAuthority();
+ if (! Connection.execute("arumate.getMegawatts", args, result)) {
+ std::cout << Connection.getError();
+ return;
+ }
+
+ // Pull the data out:
+ if (result.getType() != XmlRpcValue::TypeStruct) {
+ std::cout << "I was expecting a struct.";
+ return;
+ }
+ int i = result["n"];
+ std::string s = result["name"];
+ array = result["A"];
+ for (int i=0; i < array.size(); i++)
+ std::cout << (int)array[i] << "\n";
+ record = result["subStruct"];
+ std::cout << (std::string)record["foo"] << "\n";
+}
+
+
+
+//---------------------------- main(): -------------------------
+
+int main(int argc, char* argv[])
+{
+ BasicTest();
+ AdvancedTest();
+ return 0;
+}
+
diff --git a/SampleMain2.cpp b/SampleMain2.cpp
new file mode 100644
index 0000000..310b5cb
--- /dev/null
+++ b/SampleMain2.cpp
@@ -0,0 +1,136 @@
+#include <iostream>
+#include <time.h>
+#include "PlainXmlRpc.h"
+
+
+// main.cpp: includes both a little unit test and a sample client program.
+
+using namespace PlainXML;
+
+
+static void BasicTest()
+{
+ // Replace this URL with your own URL:
+ XmlClient Connection("https://61.95.191.232:9600/arumate/rpc/xmlRpcServer.php");
+ // Does anyone know of an XmlRpc server that I could insert here
+ // as a test machine that's always available?
+ Connection.setIgnoreCertificateAuthority();
+
+ // Call: arumate.getKilowatts(string, integer, boolean) :
+ XmlArray args;
+ args[0] = RpcVal("test");
+ args[1] = RpcVal(1);
+ args[2] = RpcVal(3.141);
+ XmlValue* result;
+
+ // Replace this function name with your own:
+ result = Connection.execute("arumate.getKilowatts", &args);
+ if (result == NULL) {
+ std::cout << Connection.getError();
+ }
+ else if (result->type() == TypeString)
+ std::cout << ((XmlString*)result)->stri;
+ else std::cout << "Success\n";
+}
+
+
+static void AdvancedTest()
+{
+ XmlArray args("params");
+ XmlValue *result;
+
+ // Passing datums:
+ args[0] = new XmlString("a string");
+ args[1] = new XmlInt(1);
+ args[2] = new XmlBool(true);
+ args[3] = new XmlDouble(3.14159);
+ time_t time1 = time(NULL);
+ struct tm* timeNow = localtime(&time1);
+ args[4] = new XmlDateTime(timeNow);
+
+ // Passing an array:
+ XmlArray array;
+ array[0] = new XmlInt(4);
+ array[1] = new XmlInt(5);
+ array[2] = new XmlDouble(6.5);
+ /* Or:*/
+ array.add(4);
+ array.add(5);
+ array.add(6.5);
+ /**/
+ args[5] = &array;
+
+ // Passing a struct:
+ XmlArray *record = new XmlArray;
+ record->set("SOURCE", "a");
+ record->set("DESTINATION", "b");
+ record->set("LENGTH", 5);
+ args[6] = record;
+
+ // What does it look like as XML?
+ std::ostringstream ostr;
+ args.toXml(ostr);
+ kstr xml = strdup(ostr.str().c_str());
+ puts(xml);
+
+ // Can we parse it back to C++ objects?
+ XmlArray &echo = *(XmlArray*)ValueFromXml(xml);
+ kstr p0 = *echo[0];
+ int p1 = *echo[1];
+ bool p2 = *echo[2];
+ double p3 = *echo[3];
+ struct tm p4;
+ echo[4]->asTmStruct(&p4);
+ time_t tmp = mktime(&p4);
+ printf("\"%s\", %d, %s, %1.4f, {%s}\n", p0, p1, (p2?"true":"false"), p3, ctime(&tmp));
+
+ // Make the call:
+ XmlClient Connection("http://localhost:9090/timetable/rpc");
+ Connection.setIgnoreCertificateAuthority();
+ result = Connection.execute("getKilowatts", &args);
+ if (result == NULL) {
+ std::cout << Connection.getError();
+ return;
+ }
+
+ // Pull the data out:
+ if (result->type() != TypeArray) {
+ std::cout << "I was expecting an array.";
+ return;
+ }
+ { double wattage;
+ int stationId;
+ bool threePhase;
+ struct tm shutdown;
+
+ XmlArray &r = *(XmlArray*)result;
+ if (r.find("wattage"))
+ wattage = *r["wattage"];
+ if (r.find("threePhase"))
+ threePhase = *r["threePhase"];
+ if (r.find("stationId"))
+ stationId = *r["stationId"];
+ if (r.find("shutdown"))
+ (*r["shutdown"]).asTmStruct(&shutdown);
+ time_t tmp = mktime(&shutdown);
+ printf("%1.4f %s %d %s\n", wattage, (threePhase?"Y":"N"), stationId, ctime(&tmp));
+ if (r.find("servers")) {
+ XmlArray &servers = *(XmlArray*)r["servers"];
+ for (int i=0; i < servers.size(); i++) {
+ XmlValue *server = servers[i];
+ printf("%s\n", (kstr)*server);
+ }
+ }
+ }
+}
+
+
+//---------------------------- main(): -------------------------
+
+int main(int argc, char* argv[])
+{
+ //BasicTest();
+ AdvancedTest();
+ return 0;
+}
+
diff --git a/TimXmlRpc.cpp b/TimXmlRpc.cpp
new file mode 100644
index 0000000..20f2317
--- /dev/null
+++ b/TimXmlRpc.cpp
@@ -0,0 +1,1749 @@
+/*
+XmlRpc C++ client for Windows
+-----------------------------
+
+Created by Dr Tim Cooper, tco@smartsgroup.com, March 2009.
+
+This lets you talk to web sites using XmlRpc from C++ on Windows. It differs
+from similar libraries as follows:
+ - works on Windows
+ - supports HTTPS (SSL)
+ - uses wininet to manage HTTP/HTTPS, so it's really very minimal
+ - much faster than XmlRpc++ which suffers from STL performance problems.
+
+This project consists of 2 files: "TimXmlRpc.h" && "TimXmlRpc.cpp".
+
+Parts of this project have been taken from Chris Morley's "XmlRpc++" project,
+in particular the API. Chris's contribution is acknowledged by marking his
+work with the token: "/*ChrisMorley/". Thanks, Chris!
+
+*/
+
+#undef UNICODE
+#include <windows.h>
+#include <wininet.h>
+#include <fstream>
+#include <iterator>
+#include "TimXmlRpc.h"
+
+
+
+
+static const char VALUE_TAG[] = "<value>";
+static const char VALUE_ETAG[] = "</value>";
+
+static const char BOOLEAN_TAG[] = "<boolean>";
+static const char BOOLEAN_ETAG[] = "</boolean>";
+static const char DOUBLE_TAG[] = "<double>";
+static const char DOUBLE_ETAG[] = "</double>";
+static const char INT_TAG[] = "<int>";
+static const char INT_ETAG[] = "</int>";
+static const char I4_TAG[] = "<i4>";
+static const char I4_ETAG[] = "</i4>";
+static const char STRING_TAG[] = "<string>";
+static const char STRING_ETAG[] = "</string>";
+static const char DATETIME_TAG[] = "<dateTime.iso8601>";
+static const char DATETIME_ETAG[] = "</dateTime.iso8601>";
+static const char BASE64_TAG[] = "<base64>";
+static const char BASE64_ETAG[] = "</base64>";
+
+static const char ARRAY_TAG[] = "<array>";
+static const char DATA_TAG[] = "<data>";
+static const char DATA_ETAG[] = "</data>";
+static const char ARRAY_ETAG[] = "</array>";
+
+static const char STRUCT_TAG[] = "<struct>";
+static const char MEMBER_TAG[] = "<member>";
+static const char NAME_TAG[] = "<name>";
+static const char NAME_ETAG[] = "</name>";
+static const char MEMBER_ETAG[] = "</member>";
+static const char STRUCT_ETAG[] = "</struct>";
+
+std::string XmlRpcValue::_doubleFormat;
+
+
+
+
+
+//---------------------------------- Misc: -------------------------------
+
+static bool strieq(const char* a, const char* b)
+{
+ return _stricmp(a, b) == 0;
+}
+
+
+static bool strbegins(const char* bigstr, const char* smallstr, bool casesensitive)
+{
+ const char* smalls = smallstr;
+ const char* bigs = bigstr;
+ while (*smalls) {
+ if (casesensitive) {
+ if (*bigs != *smalls)
+ return false;
+ else bigs++, smalls++;
+ }
+ else {
+ if (toupper(*bigs) != toupper(*smalls))
+ return false;
+ else bigs++, smalls++;
+ }
+ }
+ return true;
+}
+
+
+static void assert_failed(int line, char* filename, char* msg)
+{
+ printf("Assert failed| %s:%d %s\n", filename, line, msg);
+}
+
+#define assert(c) if (c) ; else assert_failed(__LINE__,__FILE__,#c)
+
+
+
+
+//---------------------------------- ValueArray: -------------------------------
+
+void XmlRpcValue::ValueArray::resize(int n)
+{
+ if (n >= _allocated) {
+ // Optimise growing of the array:
+ int power2 = n - 1;
+ power2 |= power2 >> 1;
+ power2 |= power2 >> 2;
+ power2 |= power2 >> 4;
+ power2 |= power2 >> 8;
+ power2 |= power2 >> 16;
+ power2++;
+
+ // Set the size:
+ A = (XmlRpcValue*)realloc(A, power2 * sizeof(XmlRpcValue));
+ memset(A + _allocated, 0, (power2 - _allocated) * sizeof(XmlRpcValue));
+ _allocated = power2;
+ }
+ _size = n;
+}
+
+
+bool XmlRpcValue::ValueArray::operator==(ValueArray &other)
+{
+ if (_size != other._size)
+ return false;
+ for (int i=0; i < _size; i++) {
+ if (A[i] != other.A[i])
+ return false;
+ }
+ return true;
+}
+
+
+XmlRpcValue::ValueArray::~ValueArray()
+{
+ for (int i=0; i < _size; i++)
+ A[i].invalidate();
+ free(A);
+}
+
+
+
+
+//---------------------------------- base64.h: -------------------------------
+ /* <Chris Morley> */
+static
+int _base64Chars[]= {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
+ 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
+ '0','1','2','3','4','5','6','7','8','9',
+ '+','/' };
+
+
+#define _0000_0011 0x03
+#define _1111_1100 0xFC
+#define _1111_0000 0xF0
+#define _0011_0000 0x30
+#define _0011_1100 0x3C
+#define _0000_1111 0x0F
+#define _1100_0000 0xC0
+#define _0011_1111 0x3F
+
+#define _EQUAL_CHAR (-1)
+#define _UNKNOWN_CHAR (-2)
+
+#define _IOS_FAILBIT std::ios_base::failbit
+#define _IOS_EOFBIT std::ios_base::eofbit
+#define _IOS_BADBIT std::ios_base::badbit
+#define _IOS_GOODBIT std::ios_base::goodbit
+
+// TEMPLATE CLASS base64_put
+class base64
+{
+public:
+
+ typedef unsigned char byte_t;
+ typedef char char_type;
+ typedef std::char_traits<char> traits_type;
+
+ // base64 requires max line length <= 72 characters
+ // you can fill end of line
+ // it may be crlf, crlfsp, noline or other class like it
+
+
+ struct crlf
+ {
+ template<class _OI>
+ _OI operator()(_OI _To) const{
+ *_To = std::char_traits<char>::to_char_type('\r'); ++_To;
+ *_To = std::char_traits<char>::to_char_type('\n'); ++_To;
+
+ return (_To);
+ }
+ };
+
+
+ struct crlfsp
+ {
+ template<class _OI>
+ _OI operator()(_OI _To) const{
+ *_To = std::char_traits<char>::to_char_type('\r'); ++_To;
+ *_To = std::char_traits<char>::to_char_type('\n'); ++_To;
+ *_To = std::char_traits<char>::to_char_type(' '); ++_To;
+
+ return (_To);
+ }
+ };
+
+ struct noline
+ {
+ template<class _OI>
+ _OI operator()(_OI _To) const{
+ return (_To);
+ }
+ };
+
+ struct three2four
+ {
+ void zero()
+ {
+ _data[0] = 0;
+ _data[1] = 0;
+ _data[2] = 0;
+ }
+
+ byte_t get_0() const
+ {
+ return _data[0];
+ }
+ byte_t get_1() const
+ {
+ return _data[1];
+ }
+ byte_t get_2() const
+ {
+ return _data[2];
+ }
+
+ void set_0(byte_t _ch)
+ {
+ _data[0] = _ch;
+ }
+
+ void set_1(byte_t _ch)
+ {
+ _data[1] = _ch;
+ }
+
+ void set_2(byte_t _ch)
+ {
+ _data[2] = _ch;
+ }
+
+ // 0000 0000 1111 1111 2222 2222
+ // xxxx xxxx xxxx xxxx xxxx xxxx
+ // 0000 0011 1111 2222 2233 3333
+
+ int b64_0() const {return (_data[0] & _1111_1100) >> 2;}
+ int b64_1() const {return ((_data[0] & _0000_0011) << 4) + ((_data[1] & _1111_0000)>>4);}
+ int b64_2() const {return ((_data[1] & _0000_1111) << 2) + ((_data[2] & _1100_0000)>>6);}
+ int b64_3() const {return (_data[2] & _0011_1111);}
+
+ void b64_0(int _ch) {_data[0] = ((_ch & _0011_1111) << 2) | (_0000_0011 & _data[0]);}
+
+ void b64_1(int _ch) {
+ _data[0] = ((_ch & _0011_0000) >> 4) | (_1111_1100 & _data[0]);
+ _data[1] = ((_ch & _0000_1111) << 4) | (_0000_1111 & _data[1]); }
+
+ void b64_2(int _ch) {
+ _data[1] = ((_ch & _0011_1100) >> 2) | (_1111_0000 & _data[1]);
+ _data[2] = ((_ch & _0000_0011) << 6) | (_0011_1111 & _data[2]); }
+
+ void b64_3(int _ch){
+ _data[2] = (_ch & _0011_1111) | (_1100_0000 & _data[2]);}
+
+ private:
+ byte_t _data[3];
+
+ };
+
+
+
+
+ template<class _II, class _OI, class _State, class _Endline>
+ _II put(_II _First, _II _Last, _OI _To, _State& _St, _Endline _Endl) const
+ {
+ three2four _3to4;
+ int line_octets = 0;
+
+ while(_First != _Last)
+ {
+ _3to4.zero();
+
+ //
+ _3to4.set_0(*_First);
+ _First++;
+
+ if(_First == _Last)
+ {
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type('='); ++_To;
+ *_To = std::char_traits<char>::to_char_type('='); ++_To;
+ goto __end;
+ }
+
+ _3to4.set_1(*_First);
+ _First++;
+
+ if(_First == _Last)
+ {
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_2()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type('='); ++_To;
+ goto __end;
+ }
+
+ _3to4.set_2(*_First);
+ _First++;
+
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_2()]); ++_To;
+ *_To = std::char_traits<char>::to_char_type(_base64Chars[_3to4.b64_3()]); ++_To;
+
+ if(line_octets == 17) // base64
+ {
+ //_To = _Endl(_To);
+ *_To = '\n'; ++_To;
+ line_octets = 0;
+ }
+ else
+ ++line_octets;
+ }
+
+ __end: ;
+
+ return (_First);
+
+ }
+
+
+ template<class _II, class _OI, class _State>
+ _II get(_II _First, _II _Last, _OI _To, _State& _St) const
+ {
+ three2four _3to4;
+ int _Char;
+
+ while(_First != _Last)
+ {
+
+ // Take octet
+ _3to4.zero();
+
+ // -- 0 --
+ // Search next valid char...
+ while((_Char = _getCharType(*_First)) < 0 && _Char == _UNKNOWN_CHAR)
+ {
+ if(++_First == _Last)
+ {
+ _St |= _IOS_FAILBIT|_IOS_EOFBIT; return _First; // unexpected EOF
+ }
+ }
+
+ if(_Char == _EQUAL_CHAR){
+ // Error! First character in octet can't be '='
+ _St |= _IOS_FAILBIT;
+ return _First;
+ }
+ else
+ _3to4.b64_0(_Char);
+
+
+ // -- 1 --
+ // Search next valid char...
+ while(++_First != _Last)
+ if((_Char = _getCharType(*_First)) != _UNKNOWN_CHAR)
+ break;
+
+ if(_First == _Last) {
+ _St |= _IOS_FAILBIT|_IOS_EOFBIT; // unexpected EOF
+ return _First;
+ }
+
+ if(_Char == _EQUAL_CHAR){
+ // Error! Second character in octet can't be '='
+ _St |= _IOS_FAILBIT;
+ return _First;
+ }
+ else
+ _3to4.b64_1(_Char);
+
+
+ // -- 2 --
+ // Search next valid char...
+ while(++_First != _Last)
+ if((_Char = _getCharType(*_First)) != _UNKNOWN_CHAR)
+ break;
+
+ if(_First == _Last) {
+ // Error! Unexpected EOF. Must be '=' or base64 character
+ _St |= _IOS_FAILBIT|_IOS_EOFBIT;
+ return _First;
+ }
+
+ if(_Char == _EQUAL_CHAR){
+ // OK!
+ _3to4.b64_2(0);
+ _3to4.b64_3(0);
+
+ // chek for EOF
+ if(++_First == _Last)
+ {
+ // Error! Unexpected EOF. Must be '='. Ignore it.
+ //_St |= _IOS_BADBIT|_IOS_EOFBIT;
+ _St |= _IOS_EOFBIT;
+ }
+ else
+ if(_getCharType(*_First) != _EQUAL_CHAR)
+ {
+ // Error! Must be '='. Ignore it.
+ //_St |= _IOS_BADBIT;
+ }
+ else
+ ++_First; // Skip '='
+
+ // write 1 byte to output
+ *_To = (byte_t) _3to4.get_0();
+ return _First;
+ }
+ else
+ _3to4.b64_2(_Char);
+
+
+ // -- 3 --
+ // Search next valid char...
+ while(++_First != _Last)
+ if((_Char = _getCharType(*_First)) != _UNKNOWN_CHAR)
+ break;
+
+ if(_First == _Last) {
+ // Unexpected EOF. It's error. But ignore it.
+ //_St |= _IOS_FAILBIT|_IOS_EOFBIT;
+ _St |= _IOS_EOFBIT;
+
+ return _First;
+ }
+
+ if(_Char == _EQUAL_CHAR)
+ {
+ // OK!
+ _3to4.b64_3(0);
+
+ // write to output 2 bytes
+ *_To = (byte_t) _3to4.get_0();
+ *_To = (byte_t) _3to4.get_1();
+
+ ++_First; // set position to next character
+
+ return _First;
+ }
+ else
+ _3to4.b64_3(_Char);
+
+
+ // write to output 3 bytes
+ *_To = (byte_t) _3to4.get_0();
+ *_To = (byte_t) _3to4.get_1();
+ *_To = (byte_t) _3to4.get_2();
+
+ ++_First;
+
+
+ } // while(_First != _Last)
+
+ return (_First);
+ }
+
+protected:
+
+ int _getCharType(int _Ch) const
+ {
+ if(_base64Chars[62] == _Ch)
+ return 62;
+
+ if(_base64Chars[63] == _Ch)
+ return 63;
+
+ if((_base64Chars[0] <= _Ch) && (_base64Chars[25] >= _Ch))
+ return _Ch - _base64Chars[0];
+
+ if((_base64Chars[26] <= _Ch) && (_base64Chars[51] >= _Ch))
+ return _Ch - _base64Chars[26] + 26;
+
+ if((_base64Chars[52] <= _Ch) && (_base64Chars[61] >= _Ch))
+ return _Ch - _base64Chars[52] + 52;
+
+ if(_Ch == std::char_traits<char>::to_int_type('='))
+ return _EQUAL_CHAR;
+
+ return _UNKNOWN_CHAR;
+ }
+
+
+};
+
+
+
+/*-----------------------------------------------------------------------*/
+
+void XmlRpcValue::invalidate()
+{
+ switch (_type) {
+ case TypeString: free(u.asString); break;
+ case TypeDateTime: delete u.asTime; break;
+ case TypeBase64: delete u.asBinary; break;
+ case TypeArray: delete u.asArray; break;
+ case TypeStruct: delete u.asStruct; break;
+ default: break;
+ }
+ _type = TypeInvalid;
+ u.asBinary = 0;
+}
+
+
+// Type checking
+void XmlRpcValue::assertTypeOrInvalid(Type t)
+{
+ if (_type == TypeInvalid || _type == TypeNil) {
+ _type = t;
+ switch (_type) { // Ensure there is a valid value for the type
+ case TypeString: u.asString = _strdup(""); break;
+ case TypeDateTime: u.asTime = new struct tm(); break;
+ case TypeBase64: u.asBinary = new BinaryData(); break;
+ case TypeArray: u.asArray = new ValueArray(); break;
+ case TypeStruct: u.asStruct = new ValueStruct(); break;
+ default: u.asBinary = 0; break;
+ }
+ }
+ else if (_type != t)
+ throw XmlRpcException("type error");
+}
+
+
+void XmlRpcValue::assertArray(int size) const
+{
+ if (_type != TypeArray)
+ throw XmlRpcException("type error: expected an array");
+ else if (int(u.asArray->size()) < size)
+ throw XmlRpcException("range error: array index too large");
+}
+
+
+void XmlRpcValue::assertArray(int size)
+{
+ if (_type == TypeInvalid) {
+ _type = TypeArray;
+ u.asArray = new ValueArray(size);
+ }
+ else if (_type == TypeArray) {
+ if (int(u.asArray->size()) < size) {
+ u.asArray->resize(size);
+ }
+ }
+ else
+ throw XmlRpcException("type error: expected an array");
+}
+
+
+void XmlRpcValue::assertStruct()
+{
+ if (_type == TypeInvalid) {
+ _type = TypeStruct;
+ u.asStruct = new ValueStruct();
+ } else if (_type != TypeStruct)
+ throw XmlRpcException("type error: expected a struct");
+}
+
+
+XmlRpcValue::ValueArray::ValueArray(ValueArray &other)
+{
+ A = NULL;
+ _size = _allocated = 0;
+ resize(other._size);
+ for (int i=0 ; i < _size; i++) {
+ A[i] = other.A[i];
+ }
+}
+
+
+/* This copy constructor does a deep copy. It's equivalent to: "XmlRpcValue(XmlRpcValue&orig);".
+Tim> In my applications, I manage to avoid using copy constructors, && if you're interested
+in performance, you should also consider whether you can avoid copy constructors, e.g. by
+passing values by reference.
+Thanks to Eric Schneider for identifying a fault with a previous version of this copy constructor.
+*/
+XmlRpcValue& XmlRpcValue::operator=(XmlRpcValue const& rhs)
+{
+ if (this != &rhs) {
+ invalidate();
+ _type = rhs._type;
+ switch (_type) {
+ case TypeBoolean: u.asBool = rhs.u.asBool; break;
+ case TypeInt: u.asInt = rhs.u.asInt; break;
+ case TypeDouble: u.asDouble = rhs.u.asDouble; break;
+ case TypeDateTime: u.asTime = new struct tm(*rhs.u.asTime); break;
+ case TypeString: u.asString = _strdup(rhs.u.asString); break;
+ case TypeBase64: u.asBinary = new BinaryData(*rhs.u.asBinary); break;
+ case TypeArray: u.asArray = new ValueArray(*rhs.u.asArray); break;
+ case TypeStruct: u.asStruct = new ValueStruct(*rhs.u.asStruct); break;
+ default: u.asBinary = 0; break;
+ }
+ }
+ return *this;
+}
+ /* </Chris Morley> */
+
+
+
+
+// Map something like: "T2-D&amp;T1" to "T2-D&T1"
+// Returns a 'strdup()' version of the input string.
+
+static char* xmlDecode(const char* s, const char* end)
+{
+ char* dest = (char*)malloc(end - s + 1);
+ char* d = dest;
+ while (s < end) {
+ if (*s != '&')
+ *d++ = *s++;
+ else if (strbegins(s, "&amp;", true))
+ *d++ = '&', s += 5;
+ else if (strbegins(s, "&quot;", true))
+ *d++ = '\"', s += 6;
+ else if (strbegins(s, "&apos;", true)/*! standard*/ || strbegins(s, "&#039;", true))
+ *d++ = '\'', s += 6;
+ else if (strbegins(s, "&lt;", true))
+ *d++ = '<', s += 4;
+ else if (strbegins(s, "&gt;", true))
+ *d++ = '>', s += 4;
+ else if (strbegins(s, "&#", true)) {
+ s += 2;
+ *d++ = atoi(s);
+ while (*s >= '0' && *s <= '9')
+ s++;
+ if (*s == ';')
+ s++;
+ }
+ else
+ *d++ = *s++; // assert(false);
+ }
+ *d = '\0';
+ return dest;
+}
+
+
+// Replace raw text with xml-encoded entities.
+
+static std::string xmlEncode(const char* s)
+{
+ std::ostringstream ostr;
+
+ while (*s) {
+ if (*s == '&')
+ ostr << "&amp;";
+ else if (*s == '<')
+ ostr << "&lt;";
+ else if (*s == '>')
+ ostr << "&gt;";
+ else if (*s == '"')
+ ostr << "&quot;";
+ else if (*s == '\'')
+ ostr << "&apos;";// Would David prefer: "&#039;" ?
+ else if (*s < ' ' || *s >= 127)
+ ostr << "&#" << int((unsigned char)*s) << ';';
+ else ostr << *s;
+ s++;
+ }
+ return ostr.str();
+}
+
+
+ /* <Chris Morley> */
+// Predicate for tm equality
+static bool tmEq(struct tm const& t1, struct tm const& t2)
+{
+ return t1.tm_sec == t2.tm_sec && t1.tm_min == t2.tm_min &&
+ t1.tm_hour == t2.tm_hour && t1.tm_mday == t1.tm_mday &&
+ t1.tm_mon == t2.tm_mon && t1.tm_year == t2.tm_year;
+}
+
+
+bool XmlRpcValue::operator==(XmlRpcValue const& other) const
+{
+ if (_type != other._type)
+ return false;
+
+ switch (_type) {
+ case TypeBoolean: return ( !u.asBool && !other.u.asBool) ||
+ ( u.asBool && other.u.asBool);
+ case TypeInt: return u.asInt == other.u.asInt;
+ case TypeDouble: return u.asDouble == other.u.asDouble;
+ case TypeDateTime: return tmEq(*u.asTime, *other.u.asTime);
+ case TypeString: return *u.asString == *other.u.asString;
+ case TypeBase64: return *u.asBinary == *other.u.asBinary;
+ case TypeArray: return *u.asArray == *other.u.asArray;
+
+ // The map<>::operator== requires the definition of value< for kcc
+ case TypeStruct: //return *u.asStruct == *other.u.asStruct;
+ {
+ if (u.asStruct->size() != other.u.asStruct->size())
+ return false;
+
+ ValueStruct::const_iterator it1=u.asStruct->begin();
+ ValueStruct::const_iterator it2=other.u.asStruct->begin();
+ while (it1 != u.asStruct->end()) {
+ const XmlRpcValue& v1 = it1->second;
+ const XmlRpcValue& v2 = it2->second;
+ if ( ! (v1 == v2))
+ return false;
+ it1++;
+ it2++;
+ }
+ return true;
+ }
+ default: break;
+ }
+ return true; // Both invalid values ...
+}
+
+
+// Works for strings, binary data, arrays, && structs.
+int XmlRpcValue::size() const
+{
+ switch (_type) {
+ case TypeString: return strlen(u.asString);
+ case TypeBase64: return int(u.asBinary->size());
+ case TypeArray: return int(u.asArray->size());
+ case TypeStruct: return int(u.asStruct->size());
+ default: break;
+ }
+
+ throw XmlRpcException("type error");
+}
+
+
+// Checks for existence of struct member
+bool XmlRpcValue::hasMember(const std::string& name) const
+{
+ return _type == TypeStruct && u.asStruct->find(name) != u.asStruct->end();
+}
+ /* </Chris Morley> */
+
+
+static void SkipWhiteSpace(const char* &s)
+{
+ while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
+ s++;
+}
+
+
+static char* GobbleTag(const char* &s, char dest[128])
+// E.g. given: "< string / >", return "<string/>"
+{
+ *dest = '\0';
+ SkipWhiteSpace(s);
+ if (*s != '<')
+ return dest;
+ char* d = dest;
+ *d++ = *s++;
+ SkipWhiteSpace(s);
+ while (*s && *s != '>') {
+ if (*s == ' ' && (d[-1] == '<' || d[-1] == '/' || s[1] == ' ' || s[1] == '/' || s[1] == '>'))
+ s++;
+ else *d++ = *s++;
+ }
+ *d++ = '>';
+ *d = '\0';
+ if (*s == '>')
+ s++;
+ return dest;
+}
+
+
+static void GobbleExpectedTag(const char* &s, const char* etag)
+{
+ char tag[128];
+ GobbleTag(s, tag);
+ if (! strieq(tag, etag))
+ throw XmlRpcException(std::string("Expecting tag: ") + etag);
+}
+
+
+// Set the value from xml. The chars at *offset into valueXml
+// should be the start of a <value> tag. Destroys any existing value.
+void XmlRpcValue::fromXml(const char* &s)
+{
+ char tag[128];
+
+ invalidate();
+
+ // Gobble the <value> tag:
+ GobbleTag(s, tag);
+ if (strieq(tag, "<value>"))
+ ; // good
+ else if (strieq(tag, "<value/>")) {
+ // Jeff Rasmussen claims that <value/> is valid XmlRpc. I think he's correct.
+ _type = TypeString;
+ u.asString = _strdup("");
+ return;
+ }
+ else
+ throw XmlRpcException(std::string("Expecting tag: <value>"));
+
+ // Gobble the type tag:
+ GobbleTag(s, tag);
+ if (*tag == '\0') {
+ // If no type is indicated, the type is string.
+ stringFromXml(s);
+ }
+ else if (strieq(tag, BOOLEAN_TAG)) {
+ boolFromXml(s);
+ GobbleExpectedTag(s, BOOLEAN_ETAG);
+ }
+ else if (strieq(tag, I4_TAG)) {
+ intFromXml(s);
+ GobbleExpectedTag(s, I4_ETAG);
+ }
+ else if (strieq(tag, INT_TAG)) {
+ intFromXml(s);
+ GobbleExpectedTag(s, INT_ETAG);
+ }
+ else if (strieq(tag, DOUBLE_TAG)) {
+ doubleFromXml(s);
+ GobbleExpectedTag(s, DOUBLE_ETAG);
+ }
+ else if (strieq(tag, STRING_TAG)) {
+ stringFromXml(s);
+ GobbleExpectedTag(s, STRING_ETAG);
+ }
+ else if (strieq(tag, DATETIME_TAG)) {
+ timeFromXml(s);
+ GobbleExpectedTag(s, DATETIME_ETAG);
+ }
+ else if (strieq(tag, BASE64_TAG)) {
+ binaryFromXml(s);
+ GobbleExpectedTag(s, BASE64_ETAG);
+ }
+ else if (strieq(tag, ARRAY_TAG)) {
+ arrayFromXml(s);
+ GobbleExpectedTag(s, ARRAY_ETAG);
+ }
+ else if (strieq(tag, STRUCT_TAG)) {
+ structFromXml(s);
+ GobbleExpectedTag(s, STRUCT_ETAG);
+ }
+ else if (strieq(tag, "<string/>")) {
+ _type = TypeString;
+ u.asString = _strdup("");
+ }
+ else if (strieq(tag, "<nil/>")) {
+ _type = TypeNil;
+ }
+ else if (strieq(tag, "<struct/>")) {
+ _type = TypeStruct;
+ u.asStruct = new ValueStruct;
+ }
+ else if (strieq(tag, VALUE_ETAG)) {
+ // "If no type is indicated, the type is string."
+ _type = TypeString;
+ u.asString = _strdup("");
+ return; // don't gobble VALUE_ETAG because we already did
+ }
+ else {
+ throw XmlRpcException(std::string("Unknown type tag: ") + tag);
+ }
+
+ GobbleExpectedTag(s, VALUE_ETAG);
+}
+
+
+// Encode the Value in xml
+void XmlRpcValue::toXml(std::ostringstream &ostr) const
+{
+ switch (_type) {
+ case TypeBoolean: return boolToXml(ostr);
+ case TypeInt: return intToXml(ostr);
+ case TypeDouble: return doubleToXml(ostr);
+ case TypeString: return stringToXml(ostr);
+ case TypeDateTime: return timeToXml(ostr);
+ case TypeBase64: return binaryToXml(ostr);
+ case TypeArray: return arrayToXml(ostr);
+ case TypeStruct: return structToXml(ostr);
+ case TypeNil: return nilToXml(ostr);
+ case TypeInvalid: throw XmlRpcException("Undefined XmlRpc value");
+ default: break;
+ }
+}
+
+
+void XmlRpcValue::boolFromXml(const char* &s)
+{
+ if (*s == '0' && s[1] == '<') {
+ _type = TypeBoolean;
+ u.asBool = false;
+ s++;
+ }
+ else if (*s == '1' && s[1] == '<') {
+ _type = TypeBoolean;
+ u.asBool = true;
+ s++;
+ }
+ else throw XmlRpcException("bad BOOL");
+}
+
+
+void XmlRpcValue::boolToXml(std::ostringstream &ostr) const
+{
+ ostr << VALUE_TAG << BOOLEAN_TAG << (u.asBool ? "1" : "0") << BOOLEAN_ETAG << VALUE_ETAG;
+}
+
+
+void XmlRpcValue::intFromXml(const char* &s)
+{
+ char* valueEnd;
+ long ivalue = strtol(s, &valueEnd, 10);
+ if (valueEnd == s)
+ throw XmlRpcException("Bad double");
+ _type = TypeInt;
+ u.asInt = int(ivalue);
+ s = valueEnd;
+}
+
+
+void XmlRpcValue::intToXml(std::ostringstream &ostr) const
+{
+ ostr << VALUE_TAG << I4_TAG << u.asInt << I4_ETAG << VALUE_ETAG;
+}
+
+
+void XmlRpcValue::doubleFromXml(const char* &s)
+{
+ char* valueEnd;
+ double dvalue = strtod(s, &valueEnd);
+ if (valueEnd == s)
+ throw XmlRpcException("Bad double");
+ _type = TypeDouble;
+ u.asDouble = dvalue;
+ s = valueEnd;
+}
+
+
+void XmlRpcValue::doubleToXml(std::ostringstream &ostr) const
+{
+ ostr << VALUE_TAG << DOUBLE_TAG << u.asDouble << DOUBLE_ETAG << VALUE_ETAG;
+ // This will use the default ostream::precision() to display the double. To display
+ // values with greater accuracy, call e.g. 'ostr.precision(12)' at the top level.
+}
+
+
+void XmlRpcValue::stringFromXml(const char* &s)
+{
+ const char* valueEnd = strchr(s, '<');
+ if (valueEnd == NULL)
+ throw XmlRpcException("Bad string");
+ _type = TypeString;
+ u.asString = xmlDecode(s, valueEnd);
+ s = valueEnd;
+}
+
+
+void XmlRpcValue::stringToXml(std::ostringstream &ostr) const
+{
+ if (u.asString == NULL || *u.asString == '\0')
+ ostr << VALUE_TAG << "<string/>" << VALUE_ETAG;
+ else ostr << VALUE_TAG << xmlEncode(u.asString) << VALUE_ETAG;
+ // The 'STRING_TAG' is optional.
+}
+
+
+void XmlRpcValue::nilToXml(std::ostringstream &ostr) const
+{
+ ostr << VALUE_TAG << "<nil/>" << VALUE_ETAG;
+}
+
+
+void XmlRpcValue::timeFromXml(const char* &s)
+{
+ const char* valueEnd = strchr(s, '<');
+ if (valueEnd == NULL)
+ throw XmlRpcException("Bad time value");
+
+ struct tm t;
+ if (sscanf_s(s, "%4d%2d%2dT%2d:%2d:%2d", &t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec) != 6)
+ throw XmlRpcException("Bad time value");
+
+ t.tm_isdst = -1;
+ t.tm_mon -= 1;
+ _type = TypeDateTime;
+ u.asTime = new struct tm(t);
+ s = valueEnd;
+}
+
+
+void XmlRpcValue::timeToXml(std::ostringstream &ostr) const
+{
+ struct tm* t = u.asTime;
+ char buf[30];
+ _snprintf_s(buf, sizeof(buf), sizeof(buf)-1,
+ "%4d%02d%02dT%02d:%02d:%02d",
+ t->tm_year,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
+
+ ostr << VALUE_TAG << DATETIME_TAG << buf << DATETIME_ETAG << VALUE_ETAG;
+}
+
+
+void XmlRpcValue::binaryFromXml(const char* &s)
+{
+ const char* valueEnd = strchr(s, '<');
+ if (valueEnd == NULL)
+ throw XmlRpcException("Bad base64");
+
+ _type = TypeBase64;
+ u.asBinary = new BinaryData();
+ // check whether base64 encodings can contain chars xml encodes...
+
+ // convert from base64 to binary
+ int iostatus = 0;
+ base64 decoder;
+ std::back_insert_iterator<BinaryData> ins = std::back_inserter(*(u.asBinary));
+ decoder.get(s, valueEnd, ins, iostatus);
+
+ s = valueEnd;
+}
+
+
+void XmlRpcValue::binaryToXml(std::ostringstream &ostr) const
+{
+ // convert to base64
+ std::vector<char> base64data;
+ int iostatus = 0;
+ base64 encoder;
+ std::back_insert_iterator<std::vector<char> > ins = std::back_inserter(base64data);
+ encoder.put(u.asBinary->begin(), u.asBinary->end(), ins, iostatus, base64::crlf());
+
+ // Wrap with xml
+ ostr << VALUE_TAG << BASE64_TAG;
+ ostr.write(&base64data[0], base64data.size());
+ ostr << BASE64_ETAG << VALUE_ETAG;
+}
+
+
+void XmlRpcValue::arrayFromXml(const char* &s)
+{
+ char tag[128];
+
+ _type = TypeArray;
+ u.asArray = new ValueArray;
+
+ GobbleTag(s, tag);
+ if (strieq(tag, "<data/>"))
+ return;
+ if (! strieq(tag, DATA_TAG))
+ throw XmlRpcException("Expecting tag: <data>");
+
+ do {
+ SkipWhiteSpace(s);
+ if (strbegins(s, DATA_ETAG, true))
+ break;
+ int n = u.asArray->size();
+ u.asArray->resize(n+1);
+ u.asArray->at(n).fromXml(s);
+ } while (true);
+
+ // Skip the trailing </data>
+ GobbleExpectedTag(s, DATA_ETAG);
+}
+
+
+void XmlRpcValue::arrayToXml(std::ostringstream &ostr) const
+{
+ ostr << VALUE_TAG << ARRAY_TAG << DATA_TAG;
+
+ int limit = int(u.asArray->size());
+ for (int i=0; i < limit; ++i)
+ u.asArray->at(i).toXml(ostr);
+
+ ostr << DATA_ETAG << ARRAY_ETAG << VALUE_ETAG;
+}
+
+
+void XmlRpcValue::structFromXml(const char* &s)
+{
+ _type = TypeStruct;
+ u.asStruct = new ValueStruct;
+
+ SkipWhiteSpace(s);
+ while (strbegins(s, MEMBER_TAG, true)) {
+ s += strlen(MEMBER_TAG);
+
+ // name
+ GobbleExpectedTag(s, NAME_TAG);
+ const char* nameEnd = strchr(s, '<');
+ if (nameEnd == NULL)
+ throw XmlRpcException("Bad 'name' tag in struct");
+ char* name = xmlDecode(s, nameEnd);
+ s = nameEnd;
+ GobbleExpectedTag(s, NAME_ETAG);
+
+ // value
+ XmlRpcValue val;
+ val.fromXml(s);
+ if ( ! val.valid()) {
+ invalidate();
+ return;
+ }
+ const std::pair<const std::string, XmlRpcValue> p(name, val);
+ u.asStruct->insert(p);
+ free(name);
+
+ GobbleExpectedTag(s, MEMBER_ETAG);
+ SkipWhiteSpace(s);
+ }
+}
+
+
+void XmlRpcValue::structToXml(std::ostringstream &ostr) const
+{
+ ostr << VALUE_TAG << STRUCT_TAG;
+
+ ValueStruct::const_iterator it;
+ for (it=u.asStruct->begin(); it!=u.asStruct->end(); ++it) {
+ ostr << MEMBER_TAG << NAME_TAG << xmlEncode(it->first.c_str()) << NAME_ETAG;
+ it->second.toXml(ostr);
+ ostr << MEMBER_ETAG;
+ }
+
+ ostr << STRUCT_ETAG << VALUE_ETAG << '\n';
+}
+
+
+bool XmlRpcValue::parseMethodResponse(const char* s)
+{
+ char xmlVersion[128];
+ char tag[128];
+
+ GobbleTag(s, xmlVersion);
+ if (! strbegins(xmlVersion, "<?xml version", false)) {
+ if (strstr(s, "<html") != NULL || strstr(s, "<HTML") != NULL)
+ throw XmlRpcException("It looks like you've configured the wrong URL. That URL is sending us HTML text, "
+ "whereas we need RPC data.");
+ else throw XmlRpcException(std::string(s));
+ }
+ GobbleTag(s, tag);
+ if (! strieq(tag, "<methodResponse>")) {
+ if (strstr(s, "<title>Bad request!</title>"))
+ throw XmlRpcException(std::string("Talking HTTP to a HTTPS server?"));
+ else if (strstr(s, "Object not found"))
+ throw XmlRpcException(std::string("Wrong URL (\"Object not found\")"));
+ else throw XmlRpcException(std::string(s));
+ }
+ SkipWhiteSpace(s);
+ if (strbegins(s, "<fault>", true)) {
+ GobbleExpectedTag(s, "<fault>");
+ fromXml(s);
+ GobbleExpectedTag(s, "</fault>");
+ return false;
+ }
+ else {
+ GobbleExpectedTag(s, "<params>");
+ GobbleExpectedTag(s, "<param>");
+ fromXml(s);
+ // There's false real need to parse the bits at the end, is there?
+ //GobbleExpectedTag(s, "</param>");
+ //GobbleExpectedTag(s, "</params>");
+ }
+ //GobbleExpectedTag(s, "</methodResponse>");
+ return true;
+}
+
+
+void XmlRpcValue::buildCall(const char* method, std::ostringstream &ostr) const
+{
+ ostr << "<?xml version=\"1.0\"?>\r\n";
+ ostr << "<methodCall><methodName>" << method << "</methodName>\r\n<params>";
+ if (getType() == XmlRpcValue::TypeArray) {
+ for (int i=0; i < size(); ++i) {
+ ostr << "<param>";
+ (*this)[i].toXml(ostr);
+ ostr << "</param>";
+ }
+ }
+ else if (getType() == XmlRpcValue::TypeInvalid) {
+ }
+ else {
+ ostr << "<param>";
+ toXml(ostr);
+ ostr << "</param>\n";
+ }
+ ostr << "</params></methodCall>\r\n";
+}
+
+
+
+
+/*-------------------------- class XmlRpcClient: ----------------------*/
+
+class XmlRpcImplementation {
+ XmlRpcClient::protocol_enum protocol;
+ bool ignoreCertificateAuthority;
+ HINTERNET hInternet;
+ HINTERNET hConnect;
+ std::string object;
+ int port;
+
+ void hadError(const char* function);
+ bool connect(const char* server);
+
+public:
+ struct BasicAuth_node {
+ getBasicAuth_UsernameAndPassword_fn FindUsernameAndPassword;
+ char username[256];
+ char password[256];
+
+ BasicAuth_node() {
+ FindUsernameAndPassword = NULL;
+ username[0] = '\0';
+ password[0] = '\0';
+ }
+ } BasicAuth;
+ XmlRpcCallback Callback;
+ void *context;
+ int totalBytes;
+ std::string errmsg;
+ int HttpErrcode;
+ bool isFault;
+
+ XmlRpcImplementation(const char* server, int port, const char* object, XmlRpcClient::protocol_enum protocol);
+ XmlRpcImplementation(const char* URI);
+ bool execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result);
+ void setCallback(XmlRpcCallback Callback, void* context)
+ { this->Callback = Callback; this->context = context; }
+ void setIgnoreCertificateAuthority(bool value) { ignoreCertificateAuthority = value; }
+ ~XmlRpcImplementation();
+};
+
+
+XmlRpcClient::XmlRpcClient(const char* server, int port, const char* object, protocol_enum protocol)
+{
+ secret = new XmlRpcImplementation(server, port, object, protocol);
+}
+
+
+XmlRpcClient::XmlRpcClient(const char* URI)
+{
+ secret = new XmlRpcImplementation(URI);
+}
+
+
+bool XmlRpcClient::execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result)
+{
+ return secret->execute(method, params, result);
+}
+
+
+std::string XmlRpcClient::getError()
+{
+ if (secret->errmsg.size() > 1254)
+ secret->errmsg.resize(1254);
+ return secret->errmsg;
+}
+
+
+void XmlRpcClient::setError(std::string msg)
+{
+ secret->errmsg = msg;
+}
+
+
+int XmlRpcClient::getHttpErrorCode()
+{
+ return secret->HttpErrcode;
+}
+
+
+void XmlRpcClient::setCallback(XmlRpcCallback Callback, void* context)
+{
+ secret->setCallback(Callback, context);
+}
+
+
+void XmlRpcClient::setBasicAuth_Callback(getBasicAuth_UsernameAndPassword_fn fn)
+{
+ secret->BasicAuth.FindUsernameAndPassword = fn;
+}
+
+
+void XmlRpcClient::setBasicAuth_UsernameAndPassword(const char* username, const char* password)
+{
+ strcpy(secret->BasicAuth.username, username);
+ strcpy(secret->BasicAuth.password, password);
+}
+
+
+void XmlRpcClient::setIgnoreCertificateAuthority(bool value)
+{
+ secret->setIgnoreCertificateAuthority(value);
+}
+
+
+bool XmlRpcClient::isFault() const
+{
+ return secret->isFault;
+}
+
+
+void XmlRpcClient::close()
+{
+ delete secret;
+ secret = NULL;
+}
+
+
+XmlRpcImplementation::XmlRpcImplementation(const char* server, int _port, const char* _object,
+ XmlRpcClient::protocol_enum _protocol)
+{
+ port = _port;
+ object = _object;
+ HttpErrcode = -1;
+ if (_protocol == XmlRpcClient::XMLRPC_AUTO)
+ protocol = (port == 80) ? XmlRpcClient::XMLRPC_HTTP :
+ (port == 443) ? XmlRpcClient::XMLRPC_HTTPS : XmlRpcClient::XMLRPC_HTTP;
+ else protocol = _protocol;
+ ignoreCertificateAuthority = false;
+ hConnect = NULL;
+ connect(server);
+}
+
+
+XmlRpcImplementation::XmlRpcImplementation(const char* URI)
+{
+ port = 0;
+ ignoreCertificateAuthority = false;
+ if (strbegins(URI, "https://", false)) {
+ protocol = XmlRpcClient::XMLRPC_HTTPS;
+ URI += 8;
+ port = 443;
+ }
+ else if (strbegins(URI, "http://", false)) {
+ protocol = XmlRpcClient::XMLRPC_HTTP;
+ URI += 7;
+ port = 80;
+ }
+ else {
+ errmsg = "The URI must begin with \"https://\" or \"http://\".";
+ return;
+ }
+ const char* t = URI;
+ while (*t != ':' && *t != '\0' && *t != '/')
+ t++;
+ std::string server(URI, t - URI);
+ if (*t == ':') {
+ t++;
+ port = atoi(t);
+ while (*t >= '0' && *t <= '9')
+ t++;
+ }
+ object = t; // should start with '/'.
+ connect(server.c_str());
+}
+
+
+bool XmlRpcImplementation::connect(const char* server)
+{
+ Callback = NULL;
+ context = NULL;
+ totalBytes = 0;
+ hInternet = InternetOpen("XmlRpc", 0, NULL, NULL, 0);
+ if (hInternet == NULL) {
+ hadError("InternetOpen");
+ return false;
+ }
+ hConnect = InternetConnect(hInternet, server, port,
+ NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)this);
+ if (hConnect == NULL) {
+ hadError("InternetConnect");
+ return false;
+ }
+ DWORD dwTimeout=999000; // 999 seconds
+ InternetSetOption(hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout, sizeof(DWORD));
+ InternetSetOption(hConnect, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout, sizeof(DWORD));
+ return true;
+}
+
+
+// Converts a GetLastError() code into a human-readable string.
+void XmlRpcImplementation::hadError(const char* function)
+{
+ errmsg = function;
+ errmsg += " : ";
+
+ int LastError = GetLastError();
+ if (LastError == ERROR_INTERNET_TIMEOUT)
+ errmsg += "Internet timeout";
+ else if (LastError == ERROR_INTERNET_INVALID_CA)
+ errmsg += "Invalid certificate authority";
+ else if (LastError == ERROR_INTERNET_SECURITY_CHANNEL_ERROR)
+ errmsg += "Talking HTTPS to an HTTP server?";
+ else if (LastError == ERROR_INTERNET_CANNOT_CONNECT)
+ errmsg += "Failed to connect";
+ else if (LastError == ERROR_INTERNET_NAME_NOT_RESOLVED)
+ errmsg += "Name not resolved";
+ else if (LastError == ERROR_INTERNET_INVALID_URL)
+ errmsg += "Invalid URL";
+ else if (LastError == ERROR_INTERNET_NAME_NOT_RESOLVED)
+ errmsg += "Domain name not resolved";
+ else if (LastError == ERROR_INTERNET_CONNECTION_RESET)
+ errmsg += "Connection reset";
+ else if (LastError == ERROR_INTERNET_NOT_INITIALIZED)
+ errmsg += "Internet not initialised";
+ else if (LastError == ERROR_INTERNET_CONNECTION_ABORTED)
+ errmsg += "Connection aborted";
+ else if (LastError == ERROR_INTERNET_SEC_CERT_REV_FAILED)
+ errmsg += "Unable to check whether security certificate was revoked or not. Is your system clock time correct?";
+ else {
+ static char* buf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ LastError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (char*)&buf,
+ 0,
+ NULL
+ );
+ if (buf == NULL) {
+ char tmp[512];
+ sprintf(tmp, "Error %d", LastError);
+ errmsg += tmp;
+ }
+ else {
+ errmsg += buf;
+ LocalFree(buf);
+ }
+ }
+}
+
+
+static void CALLBACK myInternetCallback(HINTERNET hInternet,
+ DWORD_PTR dwContext,
+ DWORD dwInternetStatus,
+ LPVOID lpvStatusInformation,
+ DWORD dwStatusInformationLength)
+{
+ XmlRpcImplementation *connection = (XmlRpcImplementation*)dwContext;
+ if (connection && connection->Callback) {
+ static char buf[512];
+ char* status;
+ switch (dwInternetStatus) {
+ case INTERNET_STATUS_RECEIVING_RESPONSE: if (connection->totalBytes == 0)
+ status = "Waiting for response";
+ else status = "Receiving response";
+ break;
+ case INTERNET_STATUS_RESPONSE_RECEIVED: status = "Response received"; break;
+ case INTERNET_STATUS_HANDLE_CLOSING: status = "Handle closing"; break;
+ case INTERNET_STATUS_REQUEST_SENT: status = "Data sent"; break;
+ case INTERNET_STATUS_SENDING_REQUEST: status = "Sending data"; break;
+ default: status = buf;
+ sprintf(buf, "Status %d", dwInternetStatus);
+ break;
+ }
+ connection->Callback(connection->context, status);
+ }
+}
+
+
+bool XmlRpcImplementation::execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result)
+{
+ errmsg = "";
+
+ if (hConnect == NULL) {
+ errmsg = "No connection";
+ return false;
+ }
+
+ // Build the request as an XML file:
+ std::ostringstream ostr;
+ try {
+ params.buildCall(method, ostr);
+ } catch (XmlRpcException e) {
+ errmsg = e.getMessage();
+ return false;
+ }
+
+ // Create the HttpOpenRequest object:
+ if (Callback)
+ Callback(context, "Sending data");
+ const char* acceptTypes[2] = { "text/*", NULL };
+ int flags = INTERNET_FLAG_DONT_CACHE;
+ flags |= INTERNET_FLAG_KEEP_CONNECTION;
+ if (protocol != XmlRpcClient::XMLRPC_HTTP)
+ flags |= INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
+RETRY:
+ HINTERNET hHttpFile = HttpOpenRequest(
+ hConnect,
+ "POST",
+ object.c_str(),
+ HTTP_VERSION,
+ NULL,
+ acceptTypes,
+ flags,
+ (DWORD_PTR)this);
+ if (hHttpFile == NULL) {
+ hadError("HttpOpenRequest");
+ return false;
+ }
+ InternetSetStatusCallback(hHttpFile, myInternetCallback);
+
+ if (ignoreCertificateAuthority) {
+ DWORD dwFlags;
+ DWORD dwBuffLen = sizeof(dwFlags);
+
+ InternetQueryOption(hHttpFile, INTERNET_OPTION_SECURITY_FLAGS,
+ (LPVOID)&dwFlags, &dwBuffLen);
+ dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
+ InternetSetOption(hHttpFile, INTERNET_OPTION_SECURITY_FLAGS,
+ &dwFlags, sizeof (dwFlags) );
+ }
+
+ // Add the 'Content-Type' && 'Content-length' headers
+ char header[255]; // Thanks, Anthony Chan.
+ sprintf(header, "Content-Type: text/xml\r\nContent-length: %d", ostr.str().size());
+ HttpAddRequestHeaders(hHttpFile, header, strlen(header), HTTP_ADDREQ_FLAG_ADD);
+
+ // Send the request:
+ if (! HttpSendRequest(hHttpFile, NULL, 0, (LPVOID)ostr.str().c_str(), ostr.str().size())) {
+ hadError("HttpSendRequest");
+ return false;
+ }
+ if (Callback)
+ Callback(context, "Data sent...");
+
+ // Read the response:
+ char* buf = NULL;
+ int len = 0;
+ do {
+ DWORD bytesAvailable;
+ if (!InternetQueryDataAvailable(hHttpFile, &bytesAvailable, 0, (DWORD_PTR)this)) {
+ hadError("InternetQueryDataAvailable");
+ break;
+ }
+ if (bytesAvailable == 0)
+ break; // This is the EOF condition.
+
+ buf = (char*)realloc(buf, len+bytesAvailable+1);
+
+ // Read the data from the HINTERNET handle.
+ DWORD bytesRead;
+ if (!InternetReadFile(hHttpFile,
+ (LPVOID)(buf + len),
+ bytesAvailable,
+ &bytesRead))
+ {
+ hadError("InternetReadFile");
+ break;
+ }
+
+ len += bytesRead;
+ buf[len] = '\0';
+ totalBytes = len;
+
+ } while (true);
+
+ // Roel Vanhout's insertion: Did we get a HTTP_STATUS_OK response? If not, why not?
+ // XMLRPC spec says always return 200 for a valid answer. So if it's anything other than
+ // 200, it's an error (i.e., no support for redirects etc.).
+ DWORD buf_size, dummy;
+ buf_size = sizeof(DWORD);
+ if (!HttpQueryInfo(hHttpFile, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &HttpErrcode, &buf_size, 0)) {
+ errmsg = "Could not query HTTP result status";
+ free(buf);
+ return false;
+ }
+
+ // What was the response?
+ if (HttpErrcode == HTTP_STATUS_OK) {
+ // good - we have our data.
+ }
+ else if (HttpErrcode == HTTP_STATUS_DENIED || HttpErrcode == HTTP_STATUS_PROXY_AUTH_REQ) {
+ if (BasicAuth.FindUsernameAndPassword) {
+ free(buf);
+ buf = NULL;
+ if (BasicAuth.FindUsernameAndPassword(BasicAuth.username[0] != '\0', BasicAuth.username, BasicAuth.password)) {
+ InternetSetOption(hConnect, INTERNET_OPTION_PROXY_USERNAME,
+ (LPVOID)BasicAuth.username, lstrlen(BasicAuth.username));
+ InternetSetOption(hConnect, INTERNET_OPTION_PROXY_PASSWORD,
+ (LPVOID)BasicAuth.password, lstrlen(BasicAuth.password));
+ goto RETRY;
+ }
+ }
+ errmsg = "HTTP Basic authentication failed. You need to provide a username and password.";
+ free(buf);
+ InternetCloseHandle(hHttpFile);
+ return false;
+ }
+ else {
+ buf_size = 0;
+ HttpQueryInfo(hHttpFile, HTTP_QUERY_STATUS_TEXT, &dummy, &buf_size, 0);
+ buf_size++; // For the '\0'
+ char* status_text = (char*)::malloc(buf_size);
+ if (!HttpQueryInfo(hHttpFile, HTTP_QUERY_STATUS_TEXT, status_text, &buf_size, 0))
+ errmsg = "Could not query HTTP result status";
+ else {
+ char buf[512];
+ sprintf(buf, "Low level (HTTP) error: %d %s", HttpErrcode, status_text);
+ errmsg = buf;
+ }
+ InternetCloseHandle(hHttpFile);
+ free(buf);
+ return false;
+ }
+
+ // Close the HttpRequest object:
+ InternetCloseHandle(hHttpFile);
+
+ // Parse the response:
+ if (len == 0) {
+ errmsg = "Invalid XMLRPC response: content size is 0";
+ free(buf); // 'buf' will always be NULL unless for some strange reason,
+ // InternetReadFile() returns 'false' on the first pass.
+ return false;
+ }
+
+ try {
+ isFault = ! result.parseMethodResponse(buf);
+ if (isFault) {
+ XmlRpcValue possible = result["faultString"];
+ if (possible.getType() == XmlRpcValue::TypeString)
+ errmsg = std::string(possible);
+ else errmsg = "unspecified error";
+ }
+ }
+ catch (XmlRpcException err) {
+ errmsg = err.getMessage();
+ }
+ free(buf);
+
+ // Finished:
+ return errmsg == "";
+}
+
+
+XmlRpcImplementation::~XmlRpcImplementation()
+{
+ if (hConnect)
+ InternetCloseHandle(hConnect);
+ if (hInternet)
+ InternetCloseHandle(hInternet);
+}
+
+
+
+//---------------------------- Unit testing: ----------------------
+
+static void RoundTrip(XmlRpcValue &a)
+{
+ std::ostringstream ostr;
+ a.toXml(ostr);
+ std::string buf = ostr.str();
+ XmlRpcValue b;
+ const char* s = buf.c_str();
+ b.fromXml(s);
+ assert(a == b);
+}
+
+
+void XmlRpcUnitTest()
+{
+ try {
+ XmlRpcValue result;
+ char buf[327680];
+ std::ifstream input("C:\\Documents && Settings\\edval\\Desktop\\Edval data\\debug.txt");
+ input.read(buf, sizeof(buf));
+ const char* s = buf;
+ result.fromXml(s);
+ for (int i=0; i < result.size(); i++) {
+ XmlRpcValue el = result[i];
+ std::string _AcademicYear = el["ACADEMIC_YEAR"];
+ int AcademicYearId = el["ACADEMIC_YEAR_ID"];
+ }
+ } catch (XmlRpcException e) {
+ }
+
+ std::vector<XmlRpcValue> V;
+ V.push_back(10);
+ V.push_back(20);
+ V.push_back(30);
+ V.push_back(40);
+ V.push_back(50);
+
+ XmlRpcValue a = "Hello you";
+ RoundTrip(a);
+
+ XmlRpcValue harry;
+ harry[0] = 56;
+ harry[1] = 560;
+ harry[2] = 115;
+ harry[3] = 145;
+ harry[4] = 35;
+
+ //5
+ XmlRpcValue binny((void*)XmlRpcUnitTest, 30);
+ RoundTrip(binny);
+
+ XmlRpcValue jenny;
+ jenny["NAME"] = "Electric boots";
+ jenny["code"] = "54121";
+ jenny["status"] = true;
+
+ //14
+ a.clear();
+ a["CHARGE"] = 505;
+ a["SPIN"] = "foo";
+ a["COLOUR"] = false;
+ a["BENNY"] = harry;
+ a["BINNY"] = binny;
+ a["JENNY"] = jenny;
+ a["EMPTY"] = "";
+ RoundTrip(a);
+
+ // Copy constructors:
+ XmlRpcValue b;
+ {
+ XmlRpcValue copy = a;
+ XmlRpcValue tmp = copy;
+ b = tmp;
+ }
+ assert(a == b);
+}
+
diff --git a/TimXmlRpc.sln b/TimXmlRpc.sln
new file mode 100644
index 0000000..376eed0
--- /dev/null
+++ b/TimXmlRpc.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimXmlRpc", "TimXmlRpc.vcproj", "{15F133BD-94DC-4E42-92AB-99DBFA3756DD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PlainAndFast", "PlainAndFast.vcproj", "{15F136BD-94DC-4E42-93AB-99DBFA3756DE}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {15F133BD-94DC-4E42-92AB-99DBFA3756DD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {15F133BD-94DC-4E42-92AB-99DBFA3756DD}.Debug|Win32.Build.0 = Debug|Win32
+ {15F133BD-94DC-4E42-92AB-99DBFA3756DD}.Release|Win32.ActiveCfg = Release|Win32
+ {15F133BD-94DC-4E42-92AB-99DBFA3756DD}.Release|Win32.Build.0 = Release|Win32
+ {15F136BD-94DC-4E42-93AB-99DBFA3756DE}.Debug|Win32.ActiveCfg = Debug|Win32
+ {15F136BD-94DC-4E42-93AB-99DBFA3756DE}.Debug|Win32.Build.0 = Debug|Win32
+ {15F136BD-94DC-4E42-93AB-99DBFA3756DE}.Release|Win32.ActiveCfg = Release|Win32
+ {15F136BD-94DC-4E42-93AB-99DBFA3756DE}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/TimXmlRpc.vcproj b/TimXmlRpc.vcproj
new file mode 100644
index 0000000..274dc4a
--- /dev/null
+++ b/TimXmlRpc.vcproj
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="TimXmlRpc"
+ ProjectGUID="{15F133BD-94DC-4E42-92AB-99DBFA3756DD}"
+ RootNamespace="TimXmlRpc"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4267,4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wininet.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\SampleMain.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\TimXmlRpc.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\timxmlrpc.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/TimXmlRpc.vs2005.vcproj b/TimXmlRpc.vs2005.vcproj
new file mode 100644
index 0000000..1cce632
--- /dev/null
+++ b/TimXmlRpc.vs2005.vcproj
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TimXmlRpc"
+ ProjectGUID="{15F133BD-94DC-4E42-92AB-99DBFA3756DD}"
+ RootNamespace="TimXmlRpc"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wininet.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\SampleMain.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\TimXmlRpc.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\timxmlrpc.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>