Hi Cozzette,

I've attached all files. Maybe it will help you to help me . Thank you! 
Remember that the problems is only with Repeated fields.

On Tuesday, July 9, 2019 at 11:27:02 PM UTC+3, Adam Cozzette wrote:
>
> My guess would be that there's a lifetime issue involving 
> DynamicMessageFactory. The factory has to outlive any messages created from 
> it via factory.GetPrototype(...)->New(). I would have to see more of the 
> code to know for sure, though.
>
> On Mon, Jul 8, 2019 at 11:55 PM Mihai Muraru <[email protected] 
> <javascript:>> wrote:
>
>> Hi,
>>
>> I have a plugin which has to modify at runtime the value of  field from a 
>> dynamic protobuf message. First in the constructor of my class I create a 
>> copy of the original message
>>   auto desc_set=gproto::FileDescriptorSet();
>>   if (!desc_set.ParseFromString(channel_info.description))
>>   {
>>     throw ExporterException("\"" + channel_info.description + "\" is no 
>> valid protobuf descriptor.");
>>   }
>>   std::string error;
>>
>>   auto proto_msg = 
>> _proto_decoder.GetProtoMessageFromDescriptorSet(desc_set, 
>> StripProtoTopicInfo(channel_info.type), error);
>>   if (proto_msg != nullptr)
>>   {
>>     _proto_msg.reset(proto_msg);
>>   }
>>   else
>>   {
>>     throw ExporterException(error);
>>   }
>>   //create a copy of original message because later we have to parse the 
>> original message with const parameter
>>   auto new_desc_set = gproto::FileDescriptorSet();
>>   new_desc_set.ParseFromString(channel_info.description);
>>
>>   _modified_msg = 
>> _proto_decoder.GetProtoMessageFromDescriptorSet(new_desc_set, 
>> StripProtoTopicInfo(channel_info.type), error);
>>
>>
>>  , then I populate the original message fields in a using 
>> void ExporterChannel::SetData(Timestamp timestamp, const MetaData& 
>> meta_data, const std::string& payload)
>> ....
>> _proto_msg->ParseFromString(payload)
>> ....
>>
>>  Then I parse the original message using a recursive function 
>> ParseProtobufMessage(_proto_msg.get(), _modified_msg, _proto_msg->
>> GetTypeName());
>> by iterate in each field using   
>> auto refl = msg->GetReflection();
>>   std::vector<const gproto::FieldDescriptor*> field_descs;
>>   refl->ListFields(*msg, &field_descs);
>>
>>  All is good until I get to repeated field.
>> refl->SetRepeatedFloat(new_msg, field_desc, index, refl->GetRepeatedFloat
>> (*msg, field_desc, index)*signal.FactorValue.toFloat() + signal.
>> OffsetValue.toFloat());
>>
>> When I come back from the function and try to :
>>  _modified_msg->SerializeToString(&new_payload_);
>>   I get this Exception error:
>>
>> [image: Capture.JPG]
>>
>> in the header:
>>
>> [image: Capture.JPG]
>> Can anyone tell me what i'm doing wrong?
>>
>> Thanks in advance!
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Protocol Buffers" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected] <javascript:>.
>> To post to this group, send email to [email protected] 
>> <javascript:>.
>> Visit this group at https://groups.google.com/group/protobuf.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/protobuf/4225aaeb-a1d1-4b76-906f-0249762dea7e%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/protobuf/4225aaeb-a1d1-4b76-906f-0249762dea7e%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/protobuf.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/protobuf/f423e4f0-5846-4fc9-8320-63dc3cd72061%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
/* ========================= eCAL LICENSE =================================
 *
 * Copyright (C) 2016 - 2019 Continental Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * ========================= eCAL LICENSE =================================
*/


#include <iomanip>
#include <sstream>
#include <google/protobuf/descriptor.pb.h>
#include <ecal/conv/fs_helpers.h>
#include "exporter_channel.h"
using namespace eCAL::conv;

ExporterChannel::ExporterChannel(const std::string& channel_name, eCAL::eh5::HDF5Meas* writer, const ChannelInfo& channel_info, const TopicsToModify& topics2modify) :
  _writer(writer),
  _topics2modify(topics2modify),
  _channel_name(channel_name),
  _channel_must_be_modified(false),
  _modified_msg(nullptr)
{
  // allow protobuf channels only
  if (channel_info.format != SerializationFormat::PROTOBUF)
  {
    throw UnsupportedChannelException("Change Signals Value Exporter works with protobuf channels only.");
  }
  // check if the channel/topic must be modified
  for (auto topic : _topics2modify.Topics)
  {
    if (topic.Name.contains(channel_info.name.c_str()))
    {
      _channel_must_be_modified = true;
      _curent_topic = topic;
      for (auto signal : topic.Signals)
      {
        signal.Name = QString(channel_info.type.c_str()) + "." + signal.Name;
        _current_signals.push_back(signal);
      }
    }
  }

  //setting up the HFD5 writer object
  _writer->SetChannelType(channel_name, "proto:" + channel_info.type);
  _writer->SetChannelDescription(channel_name, channel_info.description);

  // generate prototype protobuf message to parse serialized data dynamically
  auto desc_set=gproto::FileDescriptorSet();
  if (!desc_set.ParseFromString(channel_info.description))
  {
    throw ExporterException("\"" + channel_info.description + "\" is no valid protobuf descriptor.");
  }
  std::string error;

  auto proto_msg = _proto_decoder.GetProtoMessageFromDescriptorSet(desc_set, StripProtoTopicInfo(channel_info.type), error);
  if (proto_msg != nullptr)
  {
    _proto_msg.reset(proto_msg);
  }
  else
  {
    throw ExporterException(error);
  }
  //create a copy of original message because later we have to parse the original message with const parameter
  auto new_desc_set = gproto::FileDescriptorSet();
  new_desc_set.ParseFromString(channel_info.description);

  _modified_msg = _proto_decoder.GetProtoMessageFromDescriptorSet(new_desc_set, StripProtoTopicInfo(channel_info.type), error);
}

void ExporterChannel::SetData(Timestamp timestamp, const MetaData& meta_data, const std::string& payload)
{
  MetaData::const_iterator iter;

  iter = meta_data.find(MetaDatumKey::SENDER_TIMESTAMP);
  const auto sender_timestamp = (iter != meta_data.end()) ? iter->second.sender_timestamp : static_cast<Timestamp>(0);

  iter = meta_data.find(MetaDatumKey::SENDER_ID);
  const auto sender_id = (iter != meta_data.end()) ? iter->second.sender_id : static_cast<uint64_t>(0);

  iter = meta_data.find(MetaDatumKey::SENDER_CLOCK);
  const auto sender_clock = (iter != meta_data.end()) ? iter->second.sender_clock : static_cast<uint64_t>(0);

  //if the channel don't have to be modify we just write the channel messages in HDF5 file and return to next frame
  if (!_channel_must_be_modified)
  {
    if (!_writer->AddEntryToFile(payload.data(), payload.size(), sender_timestamp, timestamp, _channel_name, sender_id, sender_clock))
    {
      throw ExporterException("Unable to export protobuf message.");
    }
    return;
  }

  // parse protobuf from serialized data
  if (!_proto_msg->ParseFromString(payload))
  {
    throw ExporterException(" Unable to parse protobuf message with timestamp " + std::to_string(timestamp) + ".");
  }
  _modified_msg->ParseFromString(payload);
  // modify original protobuf message regarding to the input from json file
  ParseProtobufMessage(_proto_msg.get(), _modified_msg, _proto_msg->GetTypeName());
  std::string new_payload_ = "";
  _modified_msg->SerializeToString(&new_payload_);

  //write the newly modified message
  if (!_writer->AddEntryToFile(new_payload_.data(), new_payload_.size(), sender_timestamp, timestamp, _channel_name, sender_id, sender_clock))
  {
    throw ExporterException("Unable to export protobuf message.");
  }
 
}

void ExporterChannel::ParseProtobufMessage(const gproto::Message* msg, gproto::Message* new_msg, const std::string& node)
{
  auto refl = msg->GetReflection();
  std::vector<const gproto::FieldDescriptor*> field_descs;
  refl->ListFields(*msg, &field_descs);
  for (auto field_desc : field_descs)
  {
    if (!field_desc->is_repeated())
    {
      auto child_node = node + "." + field_desc->name();
      auto current_desc_set = false;
      for (auto signal : _current_signals)
      {
        if (signal.Name == QString(child_node.c_str()))
        {
          switch (field_desc->cpp_type())
          {
          case gproto::FieldDescriptor::CPPTYPE_FLOAT:
            if (signal.Type == "float")
            {
              if (signal.FactorAndOffset == true)
                refl->SetFloat(new_msg, field_desc, refl->GetFloat(*msg, field_desc)*signal.FactorValue.toFloat() + signal.OffsetValue.toFloat());
              else
                refl->SetFloat(new_msg, field_desc, signal.StaticValue.toFloat());
            }
            break;
          case gproto::FieldDescriptor::CPPTYPE_DOUBLE:
            if (signal.Type == "double")
            {
              if (signal.FactorAndOffset == true)
                refl->SetDouble(new_msg, field_desc, refl->GetDouble(*msg, field_desc)*signal.FactorValue.toDouble() + signal.OffsetValue.toDouble());
              else
                refl->SetDouble(new_msg, field_desc, signal.StaticValue.toDouble());
            }
            break;
          case gproto::FieldDescriptor::CPPTYPE_INT32:
            if (signal.Type == "int32")
            {
              if (signal.FactorAndOffset == true)
                refl->SetInt32(new_msg, field_desc, refl->GetInt32(*msg, field_desc)*signal.FactorValue.toInt() + signal.OffsetValue.toInt());
              else
                refl->SetInt32(new_msg, field_desc, signal.StaticValue.toInt());
            }
            break;
          case gproto::FieldDescriptor::CPPTYPE_INT64:
            if (signal.Type == "int64")
            {
              if (signal.FactorAndOffset == true)
                refl->SetInt64(new_msg, field_desc, refl->GetInt64(*msg, field_desc)*signal.FactorValue.toInt() + signal.OffsetValue.toInt());
              else
                refl->SetInt64(new_msg, field_desc, signal.StaticValue.toInt());
            }
            break;
          case gproto::FieldDescriptor::CPPTYPE_UINT32:
            if (signal.Type == "uint32")
            {
              if (signal.FactorAndOffset == true)
                refl->SetUInt32(new_msg, field_desc, refl->GetUInt32(*msg, field_desc)*signal.FactorValue.toUInt() + signal.OffsetValue.toUInt());
              else
                refl->SetUInt32(new_msg, field_desc, signal.StaticValue.toUInt());
            }
            break;
          case gproto::FieldDescriptor::CPPTYPE_UINT64:
            if (signal.Type == "uint64")
            {
              if (signal.FactorAndOffset == true)
                refl->SetUInt64(new_msg, field_desc, refl->GetUInt64(*msg, field_desc)*signal.FactorValue.toUInt() + signal.OffsetValue.toUInt());
              else
                refl->SetUInt64(new_msg, field_desc, signal.StaticValue.toUInt());
            }
            break;
          case gproto::FieldDescriptor::CPPTYPE_MESSAGE:
//there is a macro named GetMessage defined in windows API so it get's in conflit with it
#ifdef GetMessage
#undef GetMessage
#endif // GetMessage
            ParseProtobufMessage(&refl->GetMessage(*msg, field_desc), new_msg, child_node);
            break;
          default:
            break;
          }
          current_desc_set = true;
        }
      }
      if (!current_desc_set)
      {
        if (field_desc->cpp_type() == gproto::FieldDescriptor::CPPTYPE_MESSAGE)
        {
#ifdef GetMessage
#undef GetMessage
#endif // GetMessage
          ParseProtobufMessage(&refl->GetMessage(*msg, field_desc), new_msg, child_node);
        }
      }
    }
    else
    {
      auto field_count = refl->FieldSize(*msg, field_desc);
      auto current_desc_set = false;
      for (decltype (field_count) index = 0; index < field_count; ++index)
      {
        auto child_node = node + "." + field_desc->name() + "." + std::to_string(index);
        current_desc_set = false;
        for (auto signal : _current_signals)
        {
          if (signal.Name == QString(child_node.c_str()))
          {
            switch (field_desc->cpp_type())
            {
            case gproto::FieldDescriptor::CPPTYPE_FLOAT:

              if (signal.Type == "float")
              {
                if (signal.FactorAndOffset == true)
                  refl->SetRepeatedFloat(new_msg, field_desc, index, refl->GetRepeatedFloat(*msg, field_desc, index)*signal.FactorValue.toFloat() + signal.OffsetValue.toFloat());
                else
                  refl->SetRepeatedFloat(new_msg, field_desc, index, signal.StaticValue.toFloat());
              }
              modifyRepeatedField(refl, msg, new_msg, field_desc, index, field_count, gproto::FieldDescriptor::CPPTYPE_FLOAT);
              break;
            case gproto::FieldDescriptor::CPPTYPE_DOUBLE:
              if (signal.Type == "double")
              {
                if (signal.FactorAndOffset == true)
                  refl->SetRepeatedDouble(new_msg, field_desc, index, refl->GetRepeatedDouble(*msg, field_desc, index)*signal.FactorValue.toDouble() + signal.OffsetValue.toDouble());
                else
                  refl->SetRepeatedDouble(new_msg, field_desc, index, signal.StaticValue.toDouble());
              }
              modifyRepeatedField(refl,msg, new_msg, field_desc, index, field_count, gproto::FieldDescriptor::CPPTYPE_DOUBLE);
              break;
            case gproto::FieldDescriptor::CPPTYPE_INT32:
              if (signal.Type == "int32")
              {
                if (signal.FactorAndOffset == true)
                  refl->SetRepeatedInt32(new_msg, field_desc, index, refl->GetRepeatedInt32(*msg, field_desc, index)*signal.FactorValue.toInt() + signal.OffsetValue.toInt());
                else
                  refl->SetRepeatedInt32(new_msg, field_desc, index, signal.StaticValue.toInt());
              }
              modifyRepeatedField(refl, msg, new_msg, field_desc, index, field_count, gproto::FieldDescriptor::CPPTYPE_INT32);
              break;
            case gproto::FieldDescriptor::CPPTYPE_INT64:
              if (signal.Type == "int64")
              {
                if (signal.FactorAndOffset == true)
                  refl->SetRepeatedInt64(new_msg, field_desc, index, refl->GetRepeatedInt64(*msg, field_desc, index)*signal.FactorValue.toInt() + signal.OffsetValue.toInt());
                else
                  refl->SetRepeatedInt64(new_msg, field_desc, index, signal.StaticValue.toInt());
              }
              modifyRepeatedField(refl, msg, new_msg, field_desc, index, field_count, gproto::FieldDescriptor::CPPTYPE_INT64);
              break;
            case gproto::FieldDescriptor::CPPTYPE_UINT32:
              if (signal.Type == "uint32")
              {
                if (signal.FactorAndOffset == true)
                  refl->SetRepeatedUInt32(new_msg, field_desc, index, refl->GetRepeatedUInt32(*msg, field_desc, index)*signal.FactorValue.toUInt() + signal.OffsetValue.toUInt());
                else
                  refl->SetRepeatedUInt32(new_msg, field_desc, index, signal.StaticValue.toUInt());
              }
              modifyRepeatedField(refl, msg, new_msg, field_desc, index, field_count, gproto::FieldDescriptor::CPPTYPE_UINT32);
              break;
            case gproto::FieldDescriptor::CPPTYPE_UINT64:
              if (signal.Type == "uint64")
              {
                if (signal.FactorAndOffset == true)
                  refl->SetRepeatedUInt64(new_msg, field_desc, index, refl->GetRepeatedUInt64(*msg, field_desc, index)*signal.FactorValue.toUInt() + signal.OffsetValue.toUInt());
                else
                  refl->SetRepeatedUInt64(new_msg, field_desc, index, signal.StaticValue.toUInt());
              }
              modifyRepeatedField(refl, msg, new_msg, field_desc, index, field_count, gproto::FieldDescriptor::CPPTYPE_UINT64);
              break;
            case gproto::FieldDescriptor::CPPTYPE_MESSAGE:
              ParseProtobufMessage(&refl->GetRepeatedMessage(*msg, field_desc, index), new_msg, child_node);
              break;
            default:
              break;
            }
            current_desc_set = true;
          }
        }
        if (!current_desc_set)
        {
          if (field_desc->cpp_type() == gproto::FieldDescriptor::CPPTYPE_MESSAGE)
          {
            ParseProtobufMessage(&refl->GetRepeatedMessage(*msg, field_desc, index), new_msg, child_node);
          }
        }
      }
    }
  }
}

void ExporterChannel::modifyRepeatedField(const gproto::Reflection* reflection, const gproto::Message* msg, gproto::Message* new_msg, const gproto::FieldDescriptor* current_field, const int& current_index, const int& field_count, const gproto::FieldDescriptor::CppType type)
{
   for (auto index_ = 0; index_ < field_count; index_++)
  {
    if (index_ != current_index)
    {
      switch (type)
      {
      case gproto::FieldDescriptor::CPPTYPE_FLOAT:
        reflection->SetRepeatedFloat(new_msg, current_field, index_, reflection->GetRepeatedFloat(*msg, current_field, index_));
        break;
      case gproto::FieldDescriptor::CPPTYPE_DOUBLE:
        reflection->SetRepeatedDouble(new_msg, current_field, index_, reflection->GetRepeatedDouble(*msg, current_field, index_));
        break;
      case gproto::FieldDescriptor::CPPTYPE_INT32:
        reflection->SetRepeatedInt32(new_msg, current_field, index_, reflection->GetRepeatedInt32(*msg, current_field, index_));
        break;
      case gproto::FieldDescriptor::CPPTYPE_INT64:
        reflection->SetRepeatedInt64(new_msg, current_field, index_, reflection->GetRepeatedInt64(*msg, current_field, index_));
        break;
      case gproto::FieldDescriptor::CPPTYPE_UINT32:
        reflection->SetRepeatedUInt32(new_msg, current_field, index_, reflection->GetRepeatedUInt32(*msg, current_field, index_));
        break;
      case gproto::FieldDescriptor::CPPTYPE_UINT64:
        reflection->SetRepeatedUInt64(new_msg, current_field, index_, reflection->GetRepeatedUInt64(*msg, current_field, index_));
        break;
      default:
        break;
      }
    }
  }
}

ExporterChannel::~ExporterChannel()
{
  if (_modified_msg != nullptr)
  {
    delete _modified_msg;
    _modified_msg = nullptr;
  }
}

std::string ExporterChannel::StripProtoTopicInfo(const std::string& input)
{
  std::string topic_type = input.substr(input.find_first_of(':') + 1, input.size()); //Do you even need this line?
  topic_type = topic_type.substr(topic_type.find_last_of('.') + 1, topic_type.size());
  return topic_type;
}

/* ========================= eCAL LICENSE =================================
 *
 * Copyright (C) 2016 - 2019 Continental Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * ========================= eCAL LICENSE =================================
*/

#pragma once
#include <string>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <QtWidgets>
#include <ecal/protobuf/ecal_proto_dyn.h>
#include <ecal/conv/plugin_base.h>
#include <ecalhdf5/eh5_meas.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/reflection.h>


namespace gproto=google::protobuf;
using namespace eCAL::conv;

struct TopicsToModify
{
  struct Signal
  {
    QString Name;
    QString Type;
    bool FactorAndOffset;
    bool Static;
    QString FactorValue;
    QString OffsetValue;
    QString StaticValue;

  };

  struct Topic
  {
    QString Name;
    QString Type;
    QString Format;
    QVector <Signal> Signals;
  };
  QVector <Topic> Topics;
};

class ExporterChannel : public ExporterChannelBase
{

public:

  ExporterChannel(const std::string& channel_name, eCAL::eh5::HDF5Meas* writer, const ChannelInfo& channel_info, const TopicsToModify& topics2modify);
  virtual void SetData(Timestamp timestamp, const MetaData& meta_data, const std::string& payload);
  virtual ~ExporterChannel();

  ExporterChannel() = delete;
  ExporterChannel(const ExporterChannel&) = delete;
  ExporterChannel(ExporterChannel &&) = delete;
  ExporterChannel& operator=(const ExporterChannel &) = delete;
  ExporterChannel& operator=(ExporterChannel &&) = delete;


private:
  struct MetaDatum
  {
    Timestamp sender_timestamp;
    uint64_t sender_id;
    uint64_t sender_clock;
  };

  void ParseProtobufMessage(const gproto::Message* msg, gproto::Message* new_msg, const std::string& node = "");
  void modifyRepeatedField(const gproto::Reflection* reflection, const gproto::Message* msg, gproto::Message* new_msg, const gproto::FieldDescriptor*, const int& current_index, const int& field_count, const gproto::FieldDescriptor::CppType type);
  static std::string StripProtoTopicInfo(const std::string& input);
  std::string _channel_name;
  std::vector<Timestamp> _timestamps;
  std::vector<MetaDatum> _meta_data;
  eCAL::protobuf::CProtoDynDecoder _proto_decoder;
  std::unique_ptr<gproto::Message> _proto_msg;
  gproto::Message* _modified_msg;
  eCAL::eh5::HDF5Meas* _writer;
  TopicsToModify _topics2modify;
  TopicsToModify::Topic _curent_topic;
  QVector <TopicsToModify::Signal> _current_signals;
  bool _channel_must_be_modified;


};

Reply via email to