xmlrpcpp: Add support for Nil value type.

XML RPC has an optional Nil data type, which is used by the Python's
xmlrpclib client. Add support for Nil to xmlrpccpp, so that we can
interop with the Python client.

Related changes:
Added a function to explicitly set the type to Nil since we cannot
reuse any of the existing constructors to set the type to Nil.

BUG: 24335496
TEST: Tested with Python's xmlrpclib with "allow_none" option set to True
and passing a "None" value as a RPC method's parameter.

Change-Id: I6d02dbf0cb54cf1bd84015e316a23bed6b04bb55
diff --git a/src/XmlRpcValue.cpp b/src/XmlRpcValue.cpp
index 607b7a1..2509c1e 100644
--- a/src/XmlRpcValue.cpp
+++ b/src/XmlRpcValue.cpp
@@ -29,6 +29,7 @@
   static const char DATETIME_ETAG[] = "</dateTime.iso8601>";
   static const char BASE64_TAG[]    = "<base64>";
   static const char BASE64_ETAG[]   = "</base64>";
+  static const char NIL_TAG[]        = "<nil/>";
 
   static const char ARRAY_TAG[]     = "<array>";
   static const char DATA_TAG[]      = "<data>";
@@ -222,7 +223,9 @@
 	int afterValueOffset = *offset;
     std::string typeTag = XmlRpcUtil::getNextTag(valueXml, offset);
     bool result = false;
-    if (typeTag == BOOLEAN_TAG)
+    if (typeTag == NIL_TAG)
+      result = nilFromXml(valueXml, offset);
+    else if (typeTag == BOOLEAN_TAG)
       result = boolFromXml(valueXml, offset);
     else if (typeTag == I4_TAG || typeTag == INT_TAG)
       result = intFromXml(valueXml, offset);
@@ -257,6 +260,7 @@
   std::string XmlRpcValue::toXml() const
   {
     switch (_type) {
+      case TypeNil:      return nilToXml();
       case TypeBoolean:  return boolToXml();
       case TypeInt:      return intToXml();
       case TypeDouble:   return doubleToXml();
@@ -270,6 +274,21 @@
     return std::string();   // Invalid value
   }
 
+  // Nil
+  bool XmlRpcValue::nilFromXml(std::string const& /* valueXml */, int* /* offset */)
+  {
+    _type = TypeNil;
+    _value.asBinary = 0;
+    return true;
+  }
+
+  std::string XmlRpcValue::nilToXml() const
+  {
+    std::string xml = VALUE_TAG;
+    xml += NIL_TAG;
+    xml += VALUE_ETAG;
+    return xml;
+  }
 
   // Boolean
   bool XmlRpcValue::boolFromXml(std::string const& valueXml, int* offset)
diff --git a/src/XmlRpcValue.h b/src/XmlRpcValue.h
index 7535d4a..769fc82 100644
--- a/src/XmlRpcValue.h
+++ b/src/XmlRpcValue.h
@@ -32,7 +32,8 @@
       TypeDateTime,
       TypeBase64,
       TypeArray,
-      TypeStruct
+      TypeStruct,
+      TypeNil
     };
 
     // Non-primitive types
@@ -129,6 +130,8 @@
     //! Specify the format used to write double values.
     static void setDoubleFormat(const char* f) { _doubleFormat = f; }
 
+    //! Set the value type to Nil. This value will be encoded as <nil/> xml tag.
+    void setToNil() { assertTypeOrInvalid(TypeNil); }
 
   protected:
     // Clean up
@@ -141,6 +144,7 @@
     void assertStruct();
 
     // XML decoding
+    bool nilFromXml(std::string const& valueXml, int* offset);
     bool boolFromXml(std::string const& valueXml, int* offset);
     bool intFromXml(std::string const& valueXml, int* offset);
     bool doubleFromXml(std::string const& valueXml, int* offset);
@@ -151,6 +155,7 @@
     bool structFromXml(std::string const& valueXml, int* offset);
 
     // XML encoding
+    std::string nilToXml() const;
     std::string boolToXml() const;
     std::string intToXml() const;
     std::string doubleToXml() const;