rosx_introspection/src/ros_parser.cpp
Go to the documentation of this file.
1 /***** MIT License ****
2 *
3 * Copyright (c) 2016-2022 Davide Faconti
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23 
24 #include <functional>
25 
28 
29 namespace RosMsgParser
30 {
31 inline bool operator==(const std::string& a, const std::string_view& b)
32 {
33  return (a.size() == b.size() && std::strncmp(a.data(), b.data(), a.size()) == 0);
34 }
35 
36 Parser::Parser(const std::string &topic_name,
37  const ROSType &msg_type,
38  const std::string &definition)
39  : _global_warnings(&std::cerr)
40  , _topic_name(topic_name)
41  , _discard_large_array(DISCARD_LARGE_ARRAYS)
42  , _max_array_size(100)
43  , _blob_policy(STORE_BLOB_AS_COPY)
44  , _dummy_root_field( new ROSField(msg_type, topic_name) )
45 {
46  auto parsed_msgs = ParseMessageDefinitions(definition, msg_type);
47  _schema = BuildMessageSchema(topic_name, parsed_msgs);
48 }
49 
50 const std::shared_ptr<MessageSchema>& Parser::getSchema() const
51 {
52  return _schema;
53 }
54 
56 {
57  for (const auto& [msg_type, msg] : _schema->msg_library) // find in the list
58  {
59  if (msg_type == type)
60  {
61  return msg;
62  }
63  }
64  return {};
65 }
66 
67 template <typename Container>
68 inline void ExpandVectorIfNecessary(Container& container, size_t new_size)
69 {
70  if (container.size() <= new_size)
71  {
72  const size_t increased_size = std::max(size_t(32), container.size() * 2);
73  container.resize(increased_size);
74  }
75 }
76 
78  FlatMessage* flat_container,
79  Deserializer* deserializer) const
80 {
81  deserializer->init(buffer);
82 
83  bool entire_message_parse = true;
84 
85  size_t value_index = 0;
86  size_t name_index = 0;
87  size_t blob_index = 0;
88  size_t blob_storage_index = 0;
89 
90  std::function<void(const ROSMessage*, FieldLeaf, bool)> deserializeImpl;
91 
92  deserializeImpl = [&](const ROSMessage* msg, FieldLeaf tree_leaf, bool store)
93  {
94  size_t index_s = 0;
95  size_t index_m = 0;
96 
97  for (const ROSField& field : msg->fields())
98  {
99  bool DO_STORE = store;
100  if (field.isConstant())
101  {
102  continue;
103  }
104 
105  const ROSType& field_type = field.type();
106 
107  auto new_tree_leaf = tree_leaf;
108  new_tree_leaf.node = tree_leaf.node->child(index_s);
109 
110  int32_t array_size = field.arraySize();
111  if (array_size == -1)
112  {
113  array_size = deserializer->deserializeUInt32();
114  }
115  if (field.isArray())
116  {
117  new_tree_leaf.index_array.push_back(0);
118  }
119 
120  bool IS_BLOB = false;
121 
122  // Stop storing it if is NOT a blob and a very large array.
123  if (array_size > static_cast<int32_t>(_max_array_size) &&
124  field_type.typeID() == BuiltinType::OTHER)
125  {
126  if (builtinSize(field_type.typeID()) == 1)
127  {
128  IS_BLOB = true;
129  }
130  else
131  {
133  {
134  DO_STORE = false;
135  }
136  entire_message_parse = false;
137  }
138  }
139 
140  if (IS_BLOB) // special case. This is a "blob", typically an image, a map, pointcloud, etc.
141  {
142  ExpandVectorIfNecessary(flat_container->blob, blob_index);
143 
144  if ( array_size > deserializer->bytesLeft() )
145  {
146  throw std::runtime_error("Buffer overrun in deserializeIntoFlatContainer (blob)");
147  }
148  if (DO_STORE)
149  {
150  flat_container->blob[blob_index].first = FieldsVector(new_tree_leaf);
151  auto& blob = flat_container->blob[blob_index].second;
152  blob_index++;
153 
155  {
156  ExpandVectorIfNecessary(flat_container->blob_storage, blob_storage_index);
157 
158  auto& storage = flat_container->blob_storage[blob_storage_index];
159  storage.resize(array_size);
160  std::memcpy(storage.data(), deserializer->getCurrentPtr(), array_size);
161  blob_storage_index++;
162 
163  blob = Span<const uint8_t>(storage.data(), storage.size());
164  }
165  else
166  {
167  blob = Span<const uint8_t>(deserializer->getCurrentPtr(), array_size);
168  }
169  }
170  deserializer->jump( array_size );
171  }
172  else // NOT a BLOB
173  {
174  bool DO_STORE_ARRAY = DO_STORE;
175  for (int i = 0; i < array_size; i++)
176  {
177  if (DO_STORE_ARRAY && i >= static_cast<int32_t>(_max_array_size))
178  {
179  DO_STORE_ARRAY = false;
180  }
181 
182  if (field.isArray() && DO_STORE_ARRAY)
183  {
184  new_tree_leaf.index_array.back() = i;
185  }
186 
187  if (field_type.typeID() == STRING)
188  {
189  ExpandVectorIfNecessary(flat_container->name, name_index);
190 
191  std::string str;
192  deserializer->deserializeString( str );
193 
194  if (DO_STORE_ARRAY)
195  {
196  flat_container->name[name_index].first = FieldsVector(new_tree_leaf);
197  flat_container->name[name_index].second = str;
198  name_index++;
199  }
200  }
201  else if (field_type.isBuiltin())
202  {
203  ExpandVectorIfNecessary(flat_container->value, value_index);
204 
205  Variant var = deserializer->deserialize(field_type.typeID());
206  if (DO_STORE_ARRAY)
207  {
208  flat_container->value[value_index] = std::make_pair(new_tree_leaf, std::move(var));
209  value_index++;
210  }
211  }
212  else
213  { // field_type.typeID() == OTHER
214  auto msg_node = field.getMessagePtr( _schema->msg_library );
215  deserializeImpl(msg_node.get(), new_tree_leaf, DO_STORE_ARRAY);
216  }
217  } // end for array_size
218  }
219 
220  if (field_type.typeID() == OTHER)
221  {
222  index_m++;
223  }
224  index_s++;
225  } // end for fields
226  }; // end of lambda
227 
228  // pass the shared_ptr
229  flat_container->schema = _schema;
230 
231  FieldLeaf rootnode;
232  rootnode.node = _schema->field_tree.croot();
233  auto root_msg = _schema->field_tree.croot()->value()->getMessagePtr( _schema->msg_library );
234 
235  deserializeImpl(root_msg.get(), rootnode, true);
236 
237  flat_container->name.resize(name_index);
238  flat_container->value.resize(value_index);
239  flat_container->blob.resize(blob_index);
240  flat_container->blob_storage.resize(blob_storage_index);
241 
242  return entire_message_parse;
243 }
244 
245 
246 void CreateRenamedValues(const FlatMessage& flat_msg, RenamedValues& renamed)
247 {
248 /* renamed.resize(flat_msg.value.size());
249  for (size_t i = 0; i < flat_msg.value.size(); i++)
250  {
251  const auto& in = flat_msg.value[i];
252  auto& out = renamed[i];
253  in.first.toStr(out.first);
254  out.second = in.second.convert<double>();
255  }*/
256 }
257 
258 
259 
260 } // namespace RosMsgParser
std::vector< std::pair< FieldsVector, std::string > > name
List of all those parsed fields that can be represented by a "string".
Definition: ros_parser.hpp:41
void ExpandVectorIfNecessary(Container &container, size_t new_size)
BuiltinType typeID() const
If type is builtin, returns the id. BuiltinType::OTHER otherwise.
Definition: ros_type.hpp:125
virtual void jump(size_t bytes)=0
virtual void init(Span< const uint8_t > buffer)
virtual void deserializeString(std::string &out)=0
std::vector< std::pair< FieldsVector, Span< const uint8_t > > > blob
Definition: ros_parser.hpp:45
std::shared_ptr< MessageSchema > _schema
Definition: ros_parser.hpp:167
bool deserialize(Span< const uint8_t > buffer, FlatMessage *flat_output, Deserializer *deserializer) const
deserializeIntoFlatContainer takes a raw buffer of memory and extract information from it...
std::shared_ptr< ROSMessage > Ptr
Definition: ros_message.hpp:37
const std::vector< ROSField > & fields() const
Definition: ros_message.hpp:45
virtual size_t bytesLeft() const
const FieldTreeNode * node
basic_string_view< char > string_view
Definition: core.h:522
ROSMessage::Ptr getMessageByType(const ROSType &type) const
type
Definition: core.h:1059
virtual const uint8_t * getCurrentPtr() const =0
Definition: core.h:760
A ROSMessage will contain one or more ROSField(s). Each field is little more than a name / type pair...
Definition: ros_field.hpp:45
MessageSchema::Ptr BuildMessageSchema(const std::string &topic_name, const std::vector< ROSMessage::Ptr > &parsed_msgs)
virtual uint32_t deserializeUInt32()=0
auto var(V &&v)
Definition: sol.hpp:18020
const std::shared_ptr< MessageSchema > & getSchema() const
getSchema provides some metadata amout a registered ROSMessage.
std::vector< std::pair< std::string, double > > RenamedValues
Definition: ros_parser.hpp:184
BlobPolicy _blob_policy
Definition: ros_parser.hpp:178
virtual Variant deserialize(BuiltinType type)=0
MaxArrayPolicy _discard_large_array
Definition: ros_parser.hpp:176
static void field(LexState *ls, ConsControl *cc)
Definition: lparser.c:891
bool isBuiltin() const
True if the type is ROS builtin.
Definition: ros_type.hpp:115
const T & move(const T &v)
Definition: backward.hpp:394
std::shared_ptr< MessageSchema > schema
Definition: ros_parser.hpp:34
def msg_type(f)
std::vector< std::vector< uint8_t > > blob_storage
Definition: ros_parser.hpp:47
def field_type(f)
int builtinSize(const BuiltinType c)
std::vector< ROSMessage::Ptr > ParseMessageDefinitions(const std::string &multi_def, const ROSType &type)
Definition: ros_message.cpp:85
Parser(const std::string &topic_name, const ROSType &msg_type, const std::string &definition)
std::vector< std::pair< FieldsVector, Variant > > value
Definition: ros_parser.hpp:38
The FieldTreeLeaf is, as the name suggests, a leaf (terminal node) of a StringTree. It provides the pointer to the node and a list of numbers that represent the index that corresponds to the placeholder "#".
void CreateRenamedValues(const FlatMessage &flat_msg, RenamedValues &renamed)
bool operator==(const std::string &a, const std::string_view &b)


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