diff options
Diffstat (limited to 'timxmlrpc.vs2013.h')
-rw-r--r-- | timxmlrpc.vs2013.h | 383 |
1 files changed, 383 insertions, 0 deletions
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(); +}; |