diff options
-rw-r--r-- | PlainAndFast.vcproj | 206 | ||||
-rw-r--r-- | PlainXmlRpc.cpp | 1476 | ||||
-rw-r--r-- | SampleMain2.cpp | 136 | ||||
-rw-r--r-- | TimXmlRpc.sln | 6 | ||||
-rw-r--r-- | timxmlrpc.h | 389 | ||||
-rw-r--r-- | timxmlrpc.vs2013.h | 383 |
6 files changed, 772 insertions, 1824 deletions
diff --git a/PlainAndFast.vcproj b/PlainAndFast.vcproj deleted file mode 100644 index 7e3cd15..0000000 --- a/PlainAndFast.vcproj +++ /dev/null @@ -1,206 +0,0 @@ -<?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 deleted file mode 100644 index c3bc962..0000000 --- a/PlainXmlRpc.cpp +++ /dev/null @@ -1,1476 +0,0 @@ - -#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&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, "&", true)) - *d++ = '&', s += 5; - else if (strbegins(s, """, true)) - *d++ = '\"', s += 6; - else if (strbegins(s, "'", true)/*not standard*/ or strbegins(s, "'", true)) - *d++ = '\'', s += 6; - else if (strbegins(s, "<", true)) - *d++ = '<', s += 4; - else if (strbegins(s, ">", 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 << "&"; - else if (*s == '<') - ostr << "<"; - else if (*s == '>') - ostr << ">"; - else if (*s == '"') - ostr << """; - else if (*s == '\'') - ostr << "'";// Would David prefer: "'" ? - 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/SampleMain2.cpp b/SampleMain2.cpp deleted file mode 100644 index 310b5cb..0000000 --- a/SampleMain2.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#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.sln b/TimXmlRpc.sln index 376eed0..abc289d 100644 --- a/TimXmlRpc.sln +++ b/TimXmlRpc.sln @@ -3,8 +3,6 @@ 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 @@ -15,10 +13,6 @@ Global {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 diff --git a/timxmlrpc.h b/timxmlrpc.h new file mode 100644 index 0000000..8b70bf0 --- /dev/null +++ b/timxmlrpc.h @@ -0,0 +1,389 @@ +/* +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" and "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! + + +-------------------------Sample app:------------------------- + +#include <iostream> +#include "timXmlRpc.h" + +void Test(std::string username, std::string password) +{ + XmlRpcValue args, result; + + XmlRpcClient Connection("https://www.edval.com.au:9001/test.php"); + args[0] = username; + args[1] = Md5(username + "." + password); // salted Md5 + if (not Connection.execute("tetun.aprende", args, result)) { + std::cerr << "Error: " << Connection.getError() << std::endl; + } + else { + std::cout << "The answer is: " << std::string(result) << std::endl; + } +} + + +See 'SampleMain.cpp' for a more elaborate example. + +*/ + + + +#include <string> +#include <vector> +#include <map> +#include <sstream> + + + + +typedef void (*XmlRpcCallback)(void* context, char* status); + + +/* A 'get username and password' function is used for HTTP basic authentication. +It will either get the (username,password) pair from some stored location, or +prompt the user for it. + Return 'true' if the user attempted to supply the credentials, or 'false' +if they want to cancel. + Display a 'logon failed' message if 'retry'. +*/ +typedef bool (*getBasicAuth_UsernameAndPassword_fn)(bool retry, char username[256], char password[256]); + + + /* <Chris Morley> */ +class XmlRpcException { + std::string _message; + +public: + //! Constructor + //! @param message A descriptive error message + XmlRpcException(const std::string message) : + _message(message) {} + + //! Return the error message. + const std::string& getMessage() const { return _message; } +}; + /* </Chris Morley> */ + + +class XmlRpcValue { +public: + /* <Chris Morley> */ + enum Type { + TypeInvalid, + TypeBoolean, + TypeInt, + TypeDouble, + TypeString, + TypeDateTime, + TypeBase64, + TypeArray, + TypeStruct, + TypeNil + }; + + // Non-primitive types + typedef std::vector<char> BinaryData; + typedef std::map<std::string, XmlRpcValue> ValueStruct; + /* </Chris Morley> */ + + class ValueArray { + // tco> I'm implementing my own 'ValueArray' instead of the original + // std::vector<> because resizing the std::vector<> calls 100's of + // constructors and destructors. Using 'vector::reserve()' is not sufficient + // to prevent these constructors/destructors from being called, because + // the C++ standard requires constructors and destructors be called whenever + // an object changes its address, as happens when the std::vector resizes. + XmlRpcValue *A; + int _size; + int _allocated; + + public: + ValueArray() { A = NULL; _size = _allocated = 0; } + ValueArray(int n) { + A = NULL; _size = _allocated = 0; + resize(n); } + ValueArray(ValueArray &other); + int size() { return _size; } + void resize(int n); + XmlRpcValue& operator[](int i) { return A[i]; } + XmlRpcValue& at(int i) { return A[i]; } + bool operator==(ValueArray &other); + void push_back(XmlRpcValue &val) { int last = _size; resize(_size + 1); A[last] = val; } + ~ValueArray(); + }; + + /* <Chris Morley> */ + + //! Constructors + XmlRpcValue() : _type(TypeInvalid) { u.asBinary = 0; } + XmlRpcValue(bool value) : _type(TypeBoolean) { u.asBool = value; } + XmlRpcValue(int value) : _type(TypeInt) { u.asInt = value; } + XmlRpcValue(double value) : _type(TypeDouble) { u.asDouble = value; } + XmlRpcValue(char value) : _type(TypeString) { + u.asString = (char*)malloc(2); + u.asString[0] = value; + u.asString[1] = '\0'; + } + + XmlRpcValue(std::string const& value) : _type(TypeString) + { u.asString = _strdup(value.c_str()); } + + XmlRpcValue(const char* value) : _type(TypeString) + { u.asString = _strdup(value); } + + XmlRpcValue(struct tm* value) : _type(TypeDateTime) + { u.asTime = new struct tm(*value); } + + XmlRpcValue(void* value, int nBytes) : _type(TypeBase64) + { + u.asBinary = new BinaryData((char*)value, ((char*)value)+nBytes); + } + + //! Copy + XmlRpcValue(XmlRpcValue const& rhs) : _type(TypeInvalid) { *this = rhs; } + + //! Destructor (make virtual if you want to subclass) + /*virtual*/ ~XmlRpcValue() { invalidate(); } + + //! Erase the current value + void clear() { invalidate(); } + + // Operators + XmlRpcValue& operator=(bool rhs) { return operator=(XmlRpcValue(rhs)); } + XmlRpcValue& operator=(int const& rhs) { return operator=(XmlRpcValue(rhs)); } + XmlRpcValue& operator=(double const& rhs) { return operator=(XmlRpcValue(rhs)); } + XmlRpcValue& operator=(const char* rhs) { return operator=(XmlRpcValue(rhs)); } + XmlRpcValue& operator=(char rhs) { return operator=(XmlRpcValue(rhs)); } + + XmlRpcValue& operator=(XmlRpcValue const& rhs); //<-- don't use copy constructors if you can avoid them! + // This does a deep copy. Often you can use references instead of using copy constructors. + + bool operator==(XmlRpcValue const& other) const; + bool operator!=(XmlRpcValue const& other) const { return !(*this == other); } + + // This is an alternative to operator std::string() that Aigner claims is needed for VS13 + std::string GetStdString() { + if (_type == TypeInt) { + char tmp[80]; + _itoa_s(u.asInt, tmp, 10); // itoa(u.asInt, tmp, 10); + return (std::string)tmp; + } + assertTypeOrInvalid(TypeString); + return std::string(u.asString); + } + +#if defined(_MSC_VER) && (_MSC_VER > 1700) + operator const std::string& () { + if (_type == TypeInt) { + char tmp[80]; + _itoa_s(u.asInt, tmp, 10); // itoa(u.asInt, tmp, 10); + return std::move(std::string(tmp)); + } + assertTypeOrInvalid(TypeString); + return std::move(std::string(u.asString)); + } +#else + operator std::string () { return GetStdString(); } +#endif + + // There are some basic type conversions here. This might mean that your + // program parses stuff that strictly speaking it should report as a type error. + + operator bool() { assertTypeOrInvalid(TypeBoolean); + return u.asBool; + } + operator int() { + if (_type == TypeString && u.asString[0] >= '0' && u.asString[0] <= '9') + return atoi(u.asString); + if (_type == TypeDouble) + return (int)u.asDouble; + if (_type == TypeInt) + return u.asInt; + assertTypeOrInvalid(TypeInt); + return 0; + } + operator char() { assertTypeOrInvalid(TypeString); return *u.asString; } + operator double() { if (_type == TypeDouble) + return u.asDouble; + if (_type == TypeInt) + return u.asInt; + assertTypeOrInvalid(TypeDouble); + return 0; + } + operator std::string&() { + return GetStdString(); + } + + operator const char*() { assertTypeOrInvalid(TypeString); return u.asString; } + operator BinaryData&() { assertTypeOrInvalid(TypeBase64); return *u.asBinary; } + operator struct tm&() { assertTypeOrInvalid(TypeDateTime); return *u.asTime; } + operator ValueStruct&() { assertTypeOrInvalid(TypeStruct); return *u.asStruct; } // good for iterating thru fields + + XmlRpcValue const& operator[](int i) const { + assertArray(i+1); return u.asArray->at(i); + } + XmlRpcValue& operator[](int i) { assertArray(i+1); return u.asArray->at(i); } + + XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*u.asStruct)[k]; } + XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*u.asStruct)[s]; } + + // Accessors + //! Return true if the value has been set to something. + bool valid() const { return _type != TypeInvalid; } + + //! Return the type of the value stored. \see Type. + Type const &getType() const { return _type; } + + //! Return the size for string, base64, array, and struct values. + int size() const; + + //! Set up this value as an array, if not already so. This function is optional, + // because an undefined value is converted to an array implicitly the first time + // you index it with an integer e.g. arg[0] = "hello"; , however if there's a + // chance your array will be zero length then this function is compulsory. + void initAsArray() { assertArray(0); } + + //! Specify the size for array values. Array values will grow beyond this size if needed. + void setSize(int size) { assertArray(size); } + + //! Check for the existence of a struct member by name. + bool hasMember(const std::string& name) const; + + //! Decode xml. Destroys any existing value. + void fromXml(const char* &s); + + //! Encode the Value in xml + void toXml(std::ostringstream &ostr) const; + + // Formatting + //! Return the format used to write double values. + static std::string const& getDoubleFormat() { return _doubleFormat; } + + //! Specify the format used to write double values. + static void setDoubleFormat(const char* f) { _doubleFormat = f; } + + bool parseMethodResponse(const char* s); + void buildCall(const char* method, std::ostringstream &ostr) const; + +protected: + // Clean up + void invalidate(); + + // Type checking + void assertTypeOrInvalid(Type t); + void assertArray(int size) const; + void assertArray(int size); + void assertStruct(); + + // XML decoding + void boolFromXml(const char* &s); + void intFromXml(const char* &s); + void doubleFromXml(const char* &s); + void stringFromXml(const char* &s); + void timeFromXml(const char* &s); + void binaryFromXml(const char* &s); + void arrayFromXml(const char* &s); + void structFromXml(const char* &s); + + // XML encoding + void boolToXml(std::ostringstream &ostr) const; + void intToXml(std::ostringstream &ostr) const; + void doubleToXml(std::ostringstream &ostr) const; + void stringToXml(std::ostringstream &ostr) const; + void timeToXml(std::ostringstream &ostr) const; + void binaryToXml(std::ostringstream &ostr) const; + void arrayToXml(std::ostringstream &ostr) const; + void structToXml(std::ostringstream &ostr) const; + void nilToXml(std::ostringstream &ostr) const; + + // Format strings + static std::string _doubleFormat; + + // Type tag and values + Type _type; + + union { + bool asBool; + int asInt; + double asDouble; + struct tm* asTime; + char* asString; + BinaryData* asBinary; + ValueArray* asArray; + ValueStruct* asStruct; + } u; + +}; + /* </Chris Morley> */ + + +class XmlRpcClient { + class XmlRpcImplementation *secret; + +public: + enum protocol_enum { XMLRPC_AUTO=0, XMLRPC_HTTP=1, XMLRPC_HTTPS=2 }; + + //! Construct a client and attempt to connect to the server at the specified host:port address + //! @param host The name of the remote machine hosting the server + //! @param port The port on the remote machine where the server is listening + //! @param object An optional object name to be sent in the HTTP GET header + XmlRpcClient(const char* server, int port, const char* object, protocol_enum protocol=XMLRPC_AUTO); + + //! Construct a client and attempt to connect to the server at the specified URI. + //! @param URI (Commonly and previously known as "URL"): e.g. "https://www.edval.com.au:9001/test.php" + XmlRpcClient(const char* URI); + + ~XmlRpcClient() { close(); } + + //! Execute the named procedure on the remote server. + //! @param method The name of the remote procedure to execute + //! @param params An array of the arguments for the method + //! @param result The result value to be returned to the client + //! @return true if the request was sent and a result received + //! (although the result might be a fault). + //! + //! Currently this is a synchronous (blocking) implementation (execute + //! does not return until it receives a response or an error). Use isFault() + //! to determine whether the result is a fault response. + bool execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result); + + //! Returns true if the result of the last execute() was a fault response. + bool isFault() const; + + // Set the details for a callback function + void setCallback(XmlRpcCallback Callback, void* context); + + // Set a callback to pop up a dialog box to ask the user for credentials + void setBasicAuth_Callback(getBasicAuth_UsernameAndPassword_fn fn); + + // If you already have the credentials, pass them in here. + void setBasicAuth_UsernameAndPassword(const char* username, const char* password); + + // ignore the certificate authority on subsequent execute()'s. + void setIgnoreCertificateAuthority(bool value=true); + + // Get and set error messages: + std::string getError(); + void setError(std::string); + int getHttpErrorCode(); + + //! Close the connection + void close(); +}; diff --git a/timxmlrpc.vs2013.h b/timxmlrpc.vs2013.h new file mode 100644 index 0000000..a81001e --- /dev/null +++ b/timxmlrpc.vs2013.h @@ -0,0 +1,383 @@ +/* +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" and "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! + + +-------------------------Sample app:------------------------- + +#include <iostream> +#include "timXmlRpc.h" + +void Test(std::string username, std::string password) +{ + XmlRpcValue args, result; + + XmlRpcClient Connection("https://www.edval.com.au:9001/test.php"); + args[0] = username; + args[1] = Md5(username + "." + password); // salted Md5 + if (not Connection.execute("tetun.aprende", args, result)) { + std::cerr << "Error: " << Connection.getError() << std::endl; + } + else { + std::cout << "The answer is: " << std::string(result) << std::endl; + } +} + + +See 'SampleMain.cpp' for a more elaborate example. + +*/ + + + +#include <string> +#include <vector> +#include <map> +#include <sstream> + + + + +typedef void (*XmlRpcCallback)(void* context, char* status); + + +/* A 'get username and password' function is used for HTTP basic authentication. +It will either get the (username,password) pair from some stored location, or +prompt the user for it. + Return 'true' if the user attempted to supply the credentials, or 'false' +if they want to cancel. + Display a 'logon failed' message if 'retry'. +*/ +typedef bool (*getBasicAuth_UsernameAndPassword_fn)(bool retry, char username[256], char password[256]); + + + /* <Chris Morley> */ +class XmlRpcException { + std::string _message; + +public: + //! Constructor + //! @param message A descriptive error message + XmlRpcException(const std::string message) : + _message(message) {} + + //! Return the error message. + const std::string& getMessage() const { return _message; } +}; + /* </Chris Morley> */ + + +class XmlRpcValue { +public: + /* <Chris Morley> */ + enum Type { + TypeInvalid, + TypeBoolean, + TypeInt, + TypeDouble, + TypeString, + TypeDateTime, + TypeBase64, + TypeArray, + TypeStruct, + TypeNil + }; + + // Non-primitive types + typedef std::vector<char> BinaryData; + typedef std::map<std::string, XmlRpcValue> ValueStruct; + /* </Chris Morley> */ + + class ValueArray { + // tco> I'm implementing my own 'ValueArray' instead of the original + // std::vector<> because resizing the std::vector<> calls 100's of + // constructors and destructors. Using 'vector::reserve()' is not sufficient + // to prevent these constructors/destructors from being called, because + // the C++ standard requires constructors and destructors be called whenever + // an object changes its address, as happens when the std::vector resizes. + XmlRpcValue *A; + int _size; + int _allocated; + + public: + ValueArray() { A = NULL; _size = _allocated = 0; } + ValueArray(int n) { + A = NULL; _size = _allocated = 0; + resize(n); } + ValueArray(ValueArray &other); + int size() { return _size; } + void resize(int n); + XmlRpcValue& operator[](int i) { return A[i]; } + XmlRpcValue& at(int i) { return A[i]; } + bool operator==(ValueArray &other); + void push_back(XmlRpcValue &val) { int last = _size; resize(_size + 1); A[last] = val; } + ~ValueArray(); + }; + + /* <Chris Morley> */ + + //! Constructors + XmlRpcValue() : _type(TypeInvalid) { u.asBinary = 0; } + XmlRpcValue(bool value) : _type(TypeBoolean) { u.asBool = value; } + XmlRpcValue(int value) : _type(TypeInt) { u.asInt = value; } + XmlRpcValue(double value) : _type(TypeDouble) { u.asDouble = value; } + XmlRpcValue(char value) : _type(TypeString) { + u.asString = (char*)malloc(2); + u.asString[0] = value; + u.asString[1] = '\0'; + } + + XmlRpcValue(std::string const& value) : _type(TypeString) + { u.asString = _strdup(value.c_str()); } + + XmlRpcValue(const char* value) : _type(TypeString) + { u.asString = _strdup(value); } + + XmlRpcValue(struct tm* value) : _type(TypeDateTime) + { u.asTime = new struct tm(*value); } + + XmlRpcValue(void* value, int nBytes) : _type(TypeBase64) + { + u.asBinary = new BinaryData((char*)value, ((char*)value)+nBytes); + } + + //! Copy + XmlRpcValue(XmlRpcValue const& rhs) : _type(TypeInvalid) { *this = rhs; } + + //! Destructor (make virtual if you want to subclass) + /*virtual*/ ~XmlRpcValue() { invalidate(); } + + //! Erase the current value + void clear() { invalidate(); } + + // Operators + XmlRpcValue& operator=(bool rhs) { return operator=(XmlRpcValue(rhs)); } + XmlRpcValue& operator=(int const& rhs) { return operator=(XmlRpcValue(rhs)); } + XmlRpcValue& operator=(double const& rhs) { return operator=(XmlRpcValue(rhs)); } + XmlRpcValue& operator=(const char* rhs) { return operator=(XmlRpcValue(rhs)); } + XmlRpcValue& operator=(char rhs) { return operator=(XmlRpcValue(rhs)); } + + XmlRpcValue& operator=(XmlRpcValue const& rhs); //<-- don't use copy constructors if you can avoid them! + // This does a deep copy. Often you can use references instead of using copy constructors. + + bool operator==(XmlRpcValue const& other) const; + bool operator!=(XmlRpcValue const& other) const { return !(*this == other); } + + // This is an alternative to operator std::string() that Aigner claims is needed for VS13 + std::string GetStdString() { + if (_type == TypeInt) { + char tmp[80]; + _itoa_s(u.asInt, tmp, 10); // itoa(u.asInt, tmp, 10); + return (std::string)tmp; + } + assertTypeOrInvalid(TypeString); + return std::string(u.asString); + } + + // There are some basic type conversions here. This might mean that your + // program parses stuff that strictly speaking it should report as a type error. + + operator bool() { assertTypeOrInvalid(TypeBoolean); + return u.asBool; + } + operator int() { + if (_type == TypeString && u.asString[0] >= '0' && u.asString[0] <= '9') + return atoi(u.asString); + if (_type == TypeDouble) + return (int)u.asDouble; + if (_type == TypeInt) + return u.asInt; + assertTypeOrInvalid(TypeInt); + return 0; + } + operator char() { assertTypeOrInvalid(TypeString); return *u.asString; } + operator double() { if (_type == TypeDouble) + return u.asDouble; + if (_type == TypeInt) + return u.asInt; + assertTypeOrInvalid(TypeDouble); + return 0; + } + operator const std::string& () + { + if (_type == TypeInt) + { + char tmp[80]; + _itoa_s(u.asInt, tmp, 10); // itoa(u.asInt, tmp, 10); + return std::move(std::string(tmp)); + } + assertTypeOrInvalid(TypeString); + return std::move(std::string(u.asString)); + } + + operator const char*() { assertTypeOrInvalid(TypeString); return u.asString; } + operator BinaryData&() { assertTypeOrInvalid(TypeBase64); return *u.asBinary; } + operator struct tm&() { assertTypeOrInvalid(TypeDateTime); return *u.asTime; } + operator ValueStruct&() { assertTypeOrInvalid(TypeStruct); return *u.asStruct; } // good for iterating thru fields + + XmlRpcValue const& operator[](int i) const { + assertArray(i+1); return u.asArray->at(i); + } + XmlRpcValue& operator[](int i) { assertArray(i+1); return u.asArray->at(i); } + + XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*u.asStruct)[k]; } + XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*u.asStruct)[s]; } + + // Accessors + //! Return true if the value has been set to something. + bool valid() const { return _type != TypeInvalid; } + + //! Return the type of the value stored. \see Type. + Type const &getType() const { return _type; } + + //! Return the size for string, base64, array, and struct values. + int size() const; + + //! Set up this value as an array, if not already so. This function is optional, + // because an undefined value is converted to an array implicitly the first time + // you index it with an integer e.g. arg[0] = "hello"; , however if there's a + // chance your array will be zero length then this function is compulsory. + void initAsArray() { assertArray(0); } + + //! Specify the size for array values. Array values will grow beyond this size if needed. + void setSize(int size) { assertArray(size); } + + //! Check for the existence of a struct member by name. + bool hasMember(const std::string& name) const; + + //! Decode xml. Destroys any existing value. + void fromXml(const char* &s); + + //! Encode the Value in xml + void toXml(std::ostringstream &ostr) const; + + // Formatting + //! Return the format used to write double values. + static std::string const& getDoubleFormat() { return _doubleFormat; } + + //! Specify the format used to write double values. + static void setDoubleFormat(const char* f) { _doubleFormat = f; } + + bool parseMethodResponse(const char* s); + void buildCall(const char* method, std::ostringstream &ostr) const; + +protected: + // Clean up + void invalidate(); + + // Type checking + void assertTypeOrInvalid(Type t); + void assertArray(int size) const; + void assertArray(int size); + void assertStruct(); + + // XML decoding + void boolFromXml(const char* &s); + void intFromXml(const char* &s); + void doubleFromXml(const char* &s); + void stringFromXml(const char* &s); + void timeFromXml(const char* &s); + void binaryFromXml(const char* &s); + void arrayFromXml(const char* &s); + void structFromXml(const char* &s); + + // XML encoding + void boolToXml(std::ostringstream &ostr) const; + void intToXml(std::ostringstream &ostr) const; + void doubleToXml(std::ostringstream &ostr) const; + void stringToXml(std::ostringstream &ostr) const; + void timeToXml(std::ostringstream &ostr) const; + void binaryToXml(std::ostringstream &ostr) const; + void arrayToXml(std::ostringstream &ostr) const; + void structToXml(std::ostringstream &ostr) const; + void nilToXml(std::ostringstream &ostr) const; + + // Format strings + static std::string _doubleFormat; + + // Type tag and values + Type _type; + + union { + bool asBool; + int asInt; + double asDouble; + struct tm* asTime; + char* asString; + BinaryData* asBinary; + ValueArray* asArray; + ValueStruct* asStruct; + } u; + +}; + /* </Chris Morley> */ + + +class XmlRpcClient { + class XmlRpcImplementation *secret; + +public: + enum protocol_enum { XMLRPC_AUTO=0, XMLRPC_HTTP=1, XMLRPC_HTTPS=2 }; + + //! Construct a client and attempt to connect to the server at the specified host:port address + //! @param host The name of the remote machine hosting the server + //! @param port The port on the remote machine where the server is listening + //! @param object An optional object name to be sent in the HTTP GET header + XmlRpcClient(const char* server, int port, const char* object, protocol_enum protocol=XMLRPC_AUTO); + + //! Construct a client and attempt to connect to the server at the specified URI. + //! @param URI (Commonly and previously known as "URL"): e.g. "https://www.edval.com.au:9001/test.php" + XmlRpcClient(const char* URI); + + ~XmlRpcClient() { close(); } + + //! Execute the named procedure on the remote server. + //! @param method The name of the remote procedure to execute + //! @param params An array of the arguments for the method + //! @param result The result value to be returned to the client + //! @return true if the request was sent and a result received + //! (although the result might be a fault). + //! + //! Currently this is a synchronous (blocking) implementation (execute + //! does not return until it receives a response or an error). Use isFault() + //! to determine whether the result is a fault response. + bool execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result); + + //! Returns true if the result of the last execute() was a fault response. + bool isFault() const; + + // Set the details for a callback function + void setCallback(XmlRpcCallback Callback, void* context); + + // Set a callback to pop up a dialog box to ask the user for credentials + void setBasicAuth_Callback(getBasicAuth_UsernameAndPassword_fn fn); + + // If you already have the credentials, pass them in here. + void setBasicAuth_UsernameAndPassword(const char* username, const char* password); + + // ignore the certificate authority on subsequent execute()'s. + void setIgnoreCertificateAuthority(bool value=true); + + // Get and set error messages: + std::string getError(); + void setError(std::string); + int getHttpErrorCode(); + + //! Close the connection + void close(); +}; |