c++serializationcorbaopendds

Serialize openDDS topic to a `std::string`


I've using OpenDDS in a project. Now, for interoperability, we need to send topics also with a custom framework to other machines. Since this custom framework allows to send strings, I'd like to serialize the topics in a string and then send them.

I was using boost::serialization, but then I've made up the idea that in order to send a topic, OpenDDS should be able to serialize a topic some way, so I should be able to pick the corresponding function and use it for serialize data.

Inspecting the code I was able to find the overload of >>= and <<= operators:

void
operator<<= (
    ::CORBA::Any &_tao_any,
    BasicType::LocalForceDataDataReader_ptr _tao_elem)
{
  BasicType::LocalForceDataDataReader_ptr _tao_objptr =
    BasicType::LocalForceDataDataReader::_duplicate (_tao_elem);
  _tao_any <<= &_tao_objptr;
}

/// Non-copying insertion.
void
operator<<= (
    ::CORBA::Any &_tao_any,
    BasicType::LocalForceDataDataReader_ptr *_tao_elem)
{
  TAO::Any_Impl_T<BasicType::LocalForceDataDataReader>::insert (
      _tao_any,
      BasicType::LocalForceDataDataReader::_tao_any_destructor,
      BasicType::_tc_LocalForceDataDataReader,
      *_tao_elem);
}

It serializes the topic into Corba::Any. It seems to work, but now I need to send the content of Corba::Any. Is there a way to put the content of Corba::Any to a string, and retrieve its data from a string? Or, in other words, how can I serialize and deserialize Corba::Any?

Or there's a better way to serialize a OpenDDS topic to a string?


Solution

  • It's possible to use TAO's serialization system to do this, but it's probably better to use what OpenDDS is using: https://github.com/objectcomputing/OpenDDS/blob/master/dds/DCPS/Serializer.h (or at least it's easier for me to write an example for since I know it much better)

    These are some functions that will serialize types to and from std::strings:

    const OpenDDS::DCPS::Encoding encoding(OpenDDS::DCPS::Encoding::KIND_XCDR2);
    
    template <typename IdlType>
    std::string serialize_to_string(const IdlType& idl_value)
    {
      const size_t xcdr_size = OpenDDS::DCPS::serialized_size(encoding, idl_value);
      ACE_Message_Block mb(xcdr_size);
      OpenDDS::DCPS::Serializer serializer(&mb, encoding);
      if (!(serializer << idl_value)) {
        throw std::runtime_error("failed to serialize");
      }
      return std::string(mb.base(), mb.length());
    }
    
    template <typename IdlType>
    IdlType deserialize_from_string(const std::string& xcdr)
    {
      ACE_Message_Block mb(xcdr.size());
      mb.copy(xcdr.c_str(), xcdr.size());
      OpenDDS::DCPS::Serializer serializer(&mb, encoding);
      IdlType idl_value;
      if (!(serializer >> idl_value)) {
        throw std::runtime_error("failed to deserialize");
      }
      return idl_value;
    }
    

    Also be careful when using std::string for any binary data like CDR to make sure it's not interpreted as a null-terminated string.