protobuf_parser.cpp
Go to the documentation of this file.
1 #include <QSettings>
2 #include <QMessageBox>
3 #include "protobuf_parser.h"
5 #include "PlotJuggler/svg_util.h"
6 
7 
8 namespace gp = google::protobuf;
9 
10 ProtobufParser::ProtobufParser(const std::string &topic_name,
11  const std::string type_name,
12  const gp::FileDescriptorSet &descriptor_set,
14  : MessageParser(topic_name, data)
15  , _proto_pool(&_proto_database)
16 {
17 
18  gp::FileDescriptorProto unused;
19 
20  for (int i = 0; i < descriptor_set.file_size(); ++i)
21  {
22  const auto& file = descriptor_set.file(i);
23  if (!_proto_database.FindFileByName(file.name(), &unused))
24  {
25  if (!_proto_database.Add(file))
26  {
27  throw std::runtime_error(
28  fmt::format("failed to add definition {} to protoDB",
29  file.name()));
30  }
31  }
32  }
33 
34  _msg_descriptor = _proto_pool.FindMessageTypeByName(type_name);
35 
36  if (_msg_descriptor == nullptr)
37  {
38  throw std::runtime_error("Cannot get message descriptor");
39  }
40 }
41 
42 bool ProtobufParser::parseMessage(const MessageRef serialized_msg,
43  double &timestamp)
44 {
45  const google::protobuf::Message* prototype_msg =
46  _msg_factory.GetPrototype(_msg_descriptor);
47 
48  google::protobuf::Message* mutable_msg = prototype_msg->New();
49  if (!mutable_msg->ParseFromArray(serialized_msg.data(),
50  serialized_msg.size()))
51  {
52  return false;
53  }
54 
55  std::function<void(const google::protobuf::Message&, const std::string&, const bool)> ParseImpl;
56 
57  ParseImpl = [&](const google::protobuf::Message& msg, const std::string& prefix, const bool is_map)
58  {
59  const gp::Reflection* reflection = msg.GetReflection();
60  const gp::Descriptor* descriptor = msg.GetDescriptor();
61  // std::vector<const FieldDescriptor*> reflection_fields;
62  // reflection->ListFields(msg, &reflection_fields);
63 
64  for (int index=0; index < descriptor->field_count(); index++)
65  {
66  auto field = descriptor->field(index);
67 
68  std::string key = prefix.empty() ?
69  field->name():
70  fmt::format("{}/{}", prefix, field->name() );
71  if (is_map) {
72  // Map messages only have 2 fields: key and value. The key will be represented in the
73  // series name so skip it, and don't uselessly append "value" to the series name for
74  // the value.
75  if (field->name() == "key") {
76  continue;
77  } else {
78  key = prefix;
79  }
80  }
81 
82  std::string suffix;
83 
84  if (!field)
85  {
86  continue;
87  }
88 
89  unsigned count = 1;
90  bool repeated = false;
91  if (field->is_repeated())
92  {
93  count = reflection->FieldSize(msg, field);
94  repeated = true;
95  }
96 
97  if( repeated && count > maxArraySize() )
98  {
99  if(clampLargeArray())
100  {
101  count = std::max(count, maxArraySize());
102  }
103  else{
104  continue;
105  }
106  }
107 
108  for(unsigned index = 0; index < count ; index++)
109  {
110  if(repeated)
111  {
112  suffix = fmt::format("[{}]", index);
113  }
114 
115  bool is_double = true;
116  double value = 0;
117  switch(field->cpp_type())
118  {
119  case gp::FieldDescriptor::CPPTYPE_DOUBLE:{
120  value = !repeated ? reflection->GetDouble(msg, field) :
121  reflection->GetRepeatedDouble(msg, field, index);
122  }break;
123  case gp::FieldDescriptor::CPPTYPE_FLOAT:{
124  auto tmp = !repeated ? reflection->GetFloat(msg, field) :
125  reflection->GetRepeatedFloat(msg, field, index);
126  value = static_cast<double>(tmp);
127  }break;
128  case gp::FieldDescriptor::CPPTYPE_UINT32:{
129  auto tmp = !repeated ? reflection->GetUInt32(msg, field) :
130  reflection->GetRepeatedUInt32(msg, field, index);
131  value = static_cast<double>(tmp);
132  }break;
133  case gp::FieldDescriptor::CPPTYPE_UINT64:{
134  auto tmp = !repeated ? reflection->GetUInt64(msg, field) :
135  reflection->GetRepeatedUInt64(msg, field, index);
136  value = static_cast<double>(tmp);
137  }break;
138  case gp::FieldDescriptor::CPPTYPE_BOOL:{
139  auto tmp = !repeated ? reflection->GetBool(msg, field) :
140  reflection->GetRepeatedBool(msg, field, index);
141  value = static_cast<double>(tmp);
142  }break;
143  case gp::FieldDescriptor::CPPTYPE_INT32:{
144  auto tmp = !repeated ? reflection->GetInt32(msg, field) :
145  reflection->GetRepeatedInt32(msg, field, index);
146  value = static_cast<double>(tmp);
147  }break;
148  case gp::FieldDescriptor::CPPTYPE_INT64:{
149  auto tmp = !repeated ? reflection->GetInt64(msg, field) :
150  reflection->GetRepeatedInt64(msg, field, index);
151  value = static_cast<double>(tmp);
152  }break;
153  case gp::FieldDescriptor::CPPTYPE_ENUM:{
154  auto tmp = !repeated ? reflection->GetEnum(msg, field) :
155  reflection->GetRepeatedEnum(msg, field, index);
156 
157  auto& series = this->getStringSeries(key + suffix);
158  series.pushBack({timestamp, tmp->name()});
159  is_double = false;
160  }break;
161  case gp::FieldDescriptor::CPPTYPE_STRING:{
162  auto tmp = !repeated ? reflection->GetString(msg, field) :
163  reflection->GetRepeatedString(msg, field, index);
164 
165  if( tmp.size() > 100 )
166  {
167  // probably a blob, skip it
168  continue;
169  }
170  auto& series = this->getStringSeries(key + suffix);
171  series.pushBack({timestamp, tmp});
172  is_double = false;
173  }break;
174  case gp::FieldDescriptor::CPPTYPE_MESSAGE:
175  {
176 // Fix macro issue in Windows
177 #pragma push_macro("GetMessage")
178 #undef GetMessage
179  const auto& new_msg = repeated ?
180  reflection->GetRepeatedMessage(msg, field, index) :
181  reflection->GetMessage(msg, field);
182 #pragma pop_macro("GetMessage")
183  if (field->is_map()) {
184  // A protobuf map looks just like a message but with a "key" and
185  // "value" field, extract the key so we can set a useful suffix.
186  const auto* map_descriptor = new_msg.GetDescriptor();
187  const auto* map_reflection = new_msg.GetReflection();
188  const auto* key_field = map_descriptor->FindFieldByName("key");
189  switch(key_field->cpp_type())
190  {
191  // A map's key is a scalar type (except floats and bytes) or a string
192  case gp::FieldDescriptor::CPPTYPE_STRING:{
193  suffix = fmt::format(
194  "/{}", map_reflection->GetString(new_msg, key_field));
195  }break;
196  case gp::FieldDescriptor::CPPTYPE_INT32:{
197  suffix = fmt::format(
198  "/{}", map_reflection->GetInt32(new_msg, key_field));
199  }break;
200  case gp::FieldDescriptor::CPPTYPE_INT64:{
201  suffix = fmt::format(
202  "/{}", map_reflection->GetInt64(new_msg, key_field));
203  }break;
204  case gp::FieldDescriptor::CPPTYPE_UINT32:{
205  suffix = fmt::format(
206  "/{}", map_reflection->GetUInt32(new_msg, key_field));
207  }break;
208  case gp::FieldDescriptor::CPPTYPE_UINT64:{
209  suffix = fmt::format(
210  "/{}", map_reflection->GetUInt64(new_msg, key_field));
211  }break;
212  }
213  }
214  ParseImpl(new_msg, key + suffix, field->is_map());
215 
216  is_double = false;
217  }break;
218  }
219 
220  if( is_double )
221  {
222  auto& series = this->getSeries(key + suffix);
223  series.pushBack({timestamp, value});
224  }
225  }
226  }
227  };
228 
229  // start recursion
230  ParseImpl(*mutable_msg, _topic_name, false);
231 
232  delete mutable_msg;
233  return true;
234 }
235 
ProtobufParser(const std::string &topic_name, const google::protobuf::Descriptor *descriptor, PlotDataMapRef &data)
size_t size() const
constexpr auto count() -> size_t
Definition: core.h:1050
std::string type_name(lua_State *L, type t)
Definition: sol.hpp:8079
static void field(LexState *ls, ConsControl *cc)
Definition: lparser.c:891
bool parseMessage(const MessageRef serialized_msg, double &timestamp) override
const uint8_t * data() const
The MessageParser is the base class used to parse a message with a specific encoding+schema.
Definition: core.h:1131
Definition: format.h:895
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
Definition: color.h:583


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:01:38