1 // ----------------------------------------------------------------------------
2 //
3 // flxmlrpc Copyright (c) 2015 by W1HKJ, Dave Freese <iam_w1hkj@w1hkj.com>
4 //
5 // XmlRpc++ Copyright (c) 2002-2008 by Chris Morley
6 //
7 // This file is part of fldigi
8 //
9 // flxmlrpc is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU Lesser General Public License as published by
11 // the Free Software Foundation; either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 // ----------------------------------------------------------------------------
17 
18 #ifndef _XMLRPCVALUE_H_
19 #define _XMLRPCVALUE_H_
20 
21 #if defined(_MSC_VER)
22 # pragma warning(disable:4786)    // identifier was truncated in debug info
23 #endif
24 
25 #include <map>
26 #include <string>
27 #include <vector>
28 #include <time.h>
29 
30 namespace XmlRpc {
31 
32   enum xmlrpc_nil_t { nil };
33 
34   //! A class to represent RPC arguments and results.
35   //! Each XmlRpcValue object contains a typed value,
36   //! where the type is determined by the initial value
37   //! assigned to the object.
38   //   should probably refcount them...
39   class XmlRpcValue {
40   public:
41 
42     //! XmlRpcValue types
43     enum Type {
44       TypeInvalid,
45       TypeNil,
46       TypeBoolean,
47       TypeInt,
48       TypeUnsigned,
49       TypeLongLong,
50       TypeDouble,
51       TypeString,
52       TypeDateTime,
53       TypeBase64,
54       TypeArray,
55       TypeStruct
56     };
57 
58     // Non-primitive types
59     typedef std::vector<unsigned char> BinaryData;
60     typedef std::vector<XmlRpcValue> ValueArray;
61     typedef std::map<std::string, XmlRpcValue> ValueStruct;
62 
63 
64     // Constructors
65     //! Construct an empty XmlRpcValue
XmlRpcValue()66     XmlRpcValue() : _type(TypeInvalid) { _value.asBinary = 0; }
67 
68     //! Construct an XmlRpcValue with a nil value
XmlRpcValue(xmlrpc_nil_t value)69     XmlRpcValue(xmlrpc_nil_t value) : _type(TypeNil) { }
70 
71     //! Construct an XmlRpcValue with a bool value
XmlRpcValue(bool value)72     XmlRpcValue(bool value) : _type(TypeBoolean) { _value.asBool = value; }
73 
74     //! Construct an XmlRpcValue with an int value
XmlRpcValue(int value)75     XmlRpcValue(int value)  : _type(TypeInt) { _value.asInt = value; }
76 
XmlRpcValue(unsigned int value)77     XmlRpcValue(unsigned int value)  : _type(TypeUnsigned) { _value.asUnsigned = value; }
78 
XmlRpcValue(long long value)79     XmlRpcValue(long long value)  : _type(TypeLongLong) { _value.asLongLong = value; }
80 
81     //! Construct an XmlRpcValue with a double value
XmlRpcValue(double value)82     XmlRpcValue(double value)  : _type(TypeDouble) { _value.asDouble = value; }
83 
84     //! Construct an XmlRpcValue with a string value
XmlRpcValue(std::string const & value)85     XmlRpcValue(std::string const& value) : _type(TypeString)
86     { _value.asString = new std::string(value); }
87 
88     //! Construct an XmlRpcValue with a string value.
89     //! @param value A null-terminated (C) string.
XmlRpcValue(const char * value)90     XmlRpcValue(const char* value)  : _type(TypeString)
91     { _value.asString = new std::string(value); }
92 
XmlRpcValue(BinaryData const & value)93     XmlRpcValue(BinaryData const& value) : _type(TypeBase64)
94     { _value.asBinary = new BinaryData(value); }
95 
XmlRpcValue(ValueStruct const & value)96     XmlRpcValue(ValueStruct const& value) : _type(TypeStruct)
97     { _value.asStruct = new ValueStruct(value); }
98 
XmlRpcValue(ValueArray const & value)99     XmlRpcValue(ValueArray const& value) : _type(TypeArray)
100     { _value.asArray = new ValueArray(value); }
101 
102     //! Construct an XmlRpcValue with a date/time value.
103     //! @param value A pointer to a struct tm (see localtime)
XmlRpcValue(struct tm * value)104     XmlRpcValue(struct tm* value)  : _type(TypeDateTime)
105     { _value.asTime = new struct tm(*value); }
106 
107     //! Construct an XmlRpcValue with a binary data value
108     //! @param value A pointer to data
109     //! @param nBytes The length of the data pointed to, in bytes
XmlRpcValue(void * value,int nBytes)110     XmlRpcValue(void* value, int nBytes)  : _type(TypeBase64)
111     {
112       _value.asBinary = new BinaryData((char*)value, ((char*)value)+nBytes);
113     }
114 
115     //! Construct from xml, beginning at *offset chars into the string, updates offset
XmlRpcValue(std::string const & xml,int * offset)116     XmlRpcValue(std::string const& xml, int* offset) : _type(TypeInvalid)
117     { if ( ! fromXml(xml,offset)) _type = TypeInvalid; }
118 
119     //! Copy constructor
XmlRpcValue(XmlRpcValue const & rhs)120     XmlRpcValue(XmlRpcValue const& rhs) : _type(TypeInvalid) { *this = rhs; }
121 
122     //! Destructor (make virtual if you want to subclass)
~XmlRpcValue()123     /*virtual*/ ~XmlRpcValue() { invalidate(); }
124 
125     //! Erase the current value
clear()126     void clear() { invalidate(); }
127 
128     // Operators
129     //! Assignment from one XmlRpcValue to this one.
130     //! @param rhs The value in rhs is copied to this value.
131     XmlRpcValue& operator=(XmlRpcValue const& rhs);
132 
133     //! Assign nil to this XmlRpcValue.
134     XmlRpcValue& operator=(xmlrpc_nil_t const& rhs) { return operator=(XmlRpcValue(rhs)); }
135 
136     //! Assign a bool to this XmlRpcValue.
137     XmlRpcValue& operator=(bool const& rhs) { return operator=(XmlRpcValue(rhs)); }
138 
139     //! Assign an int to this XmlRpcValue.
140     XmlRpcValue& operator=(int const& rhs) { return operator=(XmlRpcValue(rhs)); }
141 
142     //! Assign a double to this XmlRpcValue.
143     XmlRpcValue& operator=(double const& rhs) { return operator=(XmlRpcValue(rhs)); }
144 
145     //! Assign a string to this XmlRpcValue.
146     XmlRpcValue& operator=(const char* rhs) { return operator=(XmlRpcValue(std::string(rhs))); }
147 
148     //! Tests two XmlRpcValues for equality
149     bool operator==(XmlRpcValue const& other) const;
150 
151     //! Tests two XmlRpcValues for inequality
152     bool operator!=(XmlRpcValue const& other) const;
153 
154     //! Treat an XmlRpcValue as a bool.
155     //! Throws XmlRpcException if the value is initialized to
156     //! a type that is not TypeBoolean.
157     operator bool&()          { assertType(TypeBoolean); return _value.asBool; }
158     operator bool() const     { assertType(TypeBoolean); return _value.asBool; }
159 
160     //! Treat an XmlRpcValue as an int.
161     //! Throws XmlRpcException if the value is initialized to
162     //! a type that is not TypeInt.
163     operator int&()           { assertType(TypeInt); return _value.asInt; }
164     operator int() const      { assertType(TypeInt); return _value.asInt; }
165 
166     operator unsigned int&()           { assertType(TypeUnsigned); return _value.asUnsigned; }
167     operator unsigned int() const      { assertType(TypeUnsigned); return _value.asUnsigned; }
168 
169     operator long long&()           { assertType(TypeLongLong); return _value.asLongLong; }
170     operator long long() const      { assertType(TypeLongLong); return _value.asLongLong; }
171 
172     //! Treat an XmlRpcValue as a double.
173     //! Throws XmlRpcException if the value is initialized to
174     //! a type that is not TypeDouble.
175     operator double&()        { assertType(TypeDouble); return _value.asDouble; }
176     operator double() const   { assertType(TypeDouble); return _value.asDouble; }
177 
178     //! Treat an XmlRpcValue as a string.
179     //! Throws XmlRpcException if the value is initialized to
180     //! a type that is not TypeString.
181     operator std::string&()             { assertType(TypeString); return *_value.asString; }
182     operator std::string const&() const { assertType(TypeString); return *_value.asString; }
183 
184     //! Access the BinaryData value.
185     //! Throws XmlRpcException if the value is initialized to
186     //! a type that is not TypeBase64.
187     operator BinaryData&()              { assertType(TypeBase64); return *_value.asBinary; }
188     operator BinaryData const&() const  { assertType(TypeBase64); return *_value.asBinary; }
189 
190     //! Access the DateTime value.
191     //! Throws XmlRpcException if the value is initialized to
192     //! a type that is not TypeDateTime.
193     operator struct tm&()               { assertType(TypeDateTime); return *_value.asTime; }
194     operator struct tm const&() const   { assertType(TypeDateTime); return *_value.asTime; }
195 
196 
197     //! Const array value accessor.
198     //! Access the ith value of the array.
199     //! Throws XmlRpcException if the value is not an array or if the index i is
200     //! not a valid index for the array.
201     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
202 
203     //! Array value accessor.
204     //! Access the ith value of the array, growing the array if necessary.
205     //! Throws XmlRpcException if the value is not an array.
206     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
207 
208     //! Struct entry accessor.
209     //! Returns the value associated with the given entry, creating one if necessary.
210     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
211 
212     //! Struct entry accessor.
213     //! Returns the value associated with the given entry, creating one if necessary.
214     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
215 
216     //! Access the struct value map.
217     //! Can be used to iterate over the entries in the map to find all defined entries.
218     operator ValueStruct const&() { assertStruct(); return *_value.asStruct; }
219 
220     operator ValueArray const&() const { assertType(TypeArray); return *_value.asArray; }
221 
222     // Accessors
223     //! Return true if the value has been set to something.
valid()224     bool valid() const { return _type != TypeInvalid; }
225 
226     //! Return the type of the value stored. \see Type.
getType()227     Type const &getType() const { return _type; }
228 
229     //! Return the size for string, base64, array, and struct values.
230     int size() const;
231 
232     //! Specify the size for array values. Array values will grow beyond this size if needed.
setSize(int size)233     void setSize(int size)    { assertArray(size); }
234 
235     //! Check for the existence of a struct member by name.
236     bool hasMember(const std::string& name) const;
237 
238     //! Decode xml. Destroys any existing value.
239     bool fromXml(std::string const& valueXml, int* offset);
240 
241     //! Encode the Value in xml
242     std::string toXml() const;
243 
244     //! Write the value (no xml encoding)
245     std::ostream& write(std::ostream& os) const;
246 
247     // Formatting
248     //! Return the format used to write double values.
getDoubleFormat()249     static std::string const& getDoubleFormat() { return _doubleFormat; }
250 
251     //! Specify the format used to write double values.
setDoubleFormat(const char * f)252     static void setDoubleFormat(const char* f) { _doubleFormat = f; }
253 
254 
255   protected:
256     // Clean up
257     void invalidate();
258 
259     // Type checking. Non-const versions coerce to the desired type if currently un-typed.
260     void assertType(Type t) const;
261     void assertType(Type t);
262     void assertArray(int size) const;
263     void assertArray(int size);
264     void assertStruct();
265 
266     // XML decoding
267     bool boolFromXml(std::string const& valueXml, int* offset);
268     bool intFromXml(std::string const& valueXml, int* offset);
269     bool doubleFromXml(std::string const& valueXml, int* offset);
270     bool stringFromXml(std::string const& valueXml, int* offset);
271     bool timeFromXml(std::string const& valueXml, int* offset);
272     bool binaryFromXml(std::string const& valueXml, int* offset);
273     bool arrayFromXml(std::string const& valueXml, int* offset);
274     bool structFromXml(std::string const& valueXml, int* offset);
275 
276     // XML encoding
277     std::string nilToXml() const;
278     std::string boolToXml() const;
279     std::string intToXml() const;
280     std::string doubleToXml() const;
281     std::string stringToXml() const;
282     std::string timeToXml() const;
283     std::string binaryToXml() const;
284     std::string arrayToXml() const;
285     std::string structToXml() const;
286 
287     // Format strings
288     static std::string _doubleFormat;
289 
290     // Type tag and values
291     Type _type;
292 
293     // At some point I will split off Arrays and Structs into
294     // separate ref-counted objects for more efficient copying.
295     union {
296       bool          asBool;
297       int           asInt;
298       unsigned int  asUnsigned;
299       long long     asLongLong;
300       double        asDouble;
301       struct tm*    asTime;
302       std::string*  asString;
303       BinaryData*   asBinary;
304       ValueArray*   asArray;
305       ValueStruct*  asStruct;
306     } _value;
307 
308   };
309 } // namespace XmlRpc
310 
311 
312 std::ostream& operator<<(std::ostream& os, XmlRpc::XmlRpcValue& v);
313 
314 
315 #endif // _XMLRPCVALUE_H_
316