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; };
