Gazebo Msgs

API Reference

10.3.0
FuelMetadata.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 #ifndef GZ_MSGS_CONVERT_FUELMETADATA_HH_
18 #define GZ_MSGS_CONVERT_FUELMETADATA_HH_
19 
20 // Message Headers
21 #include "gz/msgs/fuel_metadata.pb.h"
22 
23 // Data Headers
24 #include <sstream>
25 #include <string>
26 #include <tinyxml2.h>
27 
28 #include <gz/math/SemanticVersion.hh>
29 
30 namespace gz::msgs {
31 // Inline bracket to help doxygen filtering.
32 inline namespace GZ_MSGS_VERSION_NAMESPACE {
33 
35 inline bool ConvertFuelMetadata(const std::string &_modelConfigStr,
36  msgs::FuelMetadata &_meta)
37 {
38  gz::msgs::FuelMetadata meta;
39 
40  auto trimmed = [](std::string _s) -> std::string {
41  // Left trim
42  _s.erase(_s.begin(), std::find_if(_s.begin(), _s.end(),
43  [](int c) {return !std::isspace(c);}));
44 
45  // Right trim
46  _s.erase(std::find_if(_s.rbegin(), _s.rend(),
47  [](int c) {return !std::isspace(c);}).base(), _s.end());
48 
49  return _s;
50  };
51 
52  // Load the model config into tinyxml
53  tinyxml2::XMLDocument modelConfigDoc;
54  if (modelConfigDoc.Parse(_modelConfigStr.c_str()) !=
55  tinyxml2::XML_SUCCESS)
56  {
57  std::cerr << "Unable to parse model config XML string.\n";
58  return false;
59  }
60 
61  // Get the top level <model> or <world> element.
62  tinyxml2::XMLElement *topElement = modelConfigDoc.FirstChildElement(
63  "model");
64  bool isModel = true;
65  if (!topElement)
66  {
67  topElement = modelConfigDoc.FirstChildElement("world");
68  if (!topElement)
69  {
70  std::cerr << "Model config string does not contain a "
71  << "<model> or <world> element\n";
72  return false;
73  }
74  isModel = false;
75  }
76 
77  // Read the name, which is a mandatory element.
78  tinyxml2::XMLElement *elem = topElement->FirstChildElement("name");
79  if (!elem || !elem->GetText())
80  {
81  std::cerr << "Model config string does not contain a <name> element\n";
82  return false;
83  }
84  meta.set_name(trimmed(elem->GetText()));
85 
86  // Read the version, if present.
87  elem = topElement->FirstChildElement("version");
88  if (elem && elem->GetText())
89  {
90  auto version = std::stoi(trimmed(elem->GetText()));
91  meta.set_version(version);
92  }
93 
94  // Read the description, if present.
95  elem = topElement->FirstChildElement("description");
96  if (elem && elem->GetText())
97  meta.set_description(trimmed(elem->GetText()));
98 
99  // Read the dependencies, if any.
100  elem = topElement->FirstChildElement("depend");
101  while (elem)
102  {
103  auto modelElem = elem->FirstChildElement("model");
104  if (modelElem)
105  {
106  auto uriElem = modelElem->FirstChildElement("uri");
107  if (uriElem)
108  {
109  auto dependency = meta.add_dependencies();
110  dependency->set_uri(uriElem->GetText());
111  }
112  }
113  elem = elem->NextSiblingElement("depend");
114  }
115 
116  // Read the authors, if any.
117  elem = topElement->FirstChildElement("author");
118  while (elem)
119  {
120  gz::msgs::FuelMetadata::Contact *author = meta.add_authors();
121  // Get the author name and email
122  if (elem->FirstChildElement("name") &&
123  elem->FirstChildElement("name")->GetText())
124  {
125  author->set_name(trimmed(elem->FirstChildElement("name")->GetText()));
126  }
127  if (elem->FirstChildElement("email") &&
128  elem->FirstChildElement("email")->GetText())
129  {
130  author->set_email(
131  trimmed(elem->FirstChildElement("email")->GetText()));
132  }
133 
134  elem = elem->NextSiblingElement("author");
135  }
136 
137  // Get the most recent SDF file
138  elem = topElement->FirstChildElement("sdf");
139  math::SemanticVersion maxVer;
140  while (elem)
141  {
142  if (elem->GetText() && elem->Attribute("version"))
143  {
144  std::string verStr = elem->Attribute("version");
145  math::SemanticVersion ver(trimmed(verStr));
146  if (ver > maxVer)
147  {
148  gz::msgs::Version *verMsg;
149 
150  if (isModel)
151  {
152  meta.mutable_model()->mutable_file_format()->set_name("sdf");
153  verMsg =
154  meta.mutable_model()->mutable_file_format()->mutable_version();
155  meta.mutable_model()->set_file(trimmed(elem->GetText()));
156  }
157  else
158  {
159  meta.mutable_world()->mutable_file_format()->set_name("sdf");
160  verMsg =
161  meta.mutable_world()->mutable_file_format()->mutable_version();
162  meta.mutable_world()->set_file(trimmed(elem->GetText()));
163  }
164 
165  verMsg->set_major(ver.Major());
166  verMsg->set_minor(ver.Minor());
167  verMsg->set_patch(ver.Patch());
168  verMsg->set_prerelease(ver.Prerelease());
169  verMsg->set_build(ver.Build());
170  }
171  }
172 
173  elem = elem->NextSiblingElement("sdf");
174  }
175  if (meta.model().file().empty() && meta.world().file().empty())
176  {
177  std::cerr << "Model config string does not contain an <sdf> element\n";
178  return false;
179  }
180 
181  _meta.CopyFrom(meta);
182  return true;
183 }
184 
186 inline bool ConvertFuelMetadata(const msgs::FuelMetadata &_meta,
187  std::string &_modelConfigStr)
188 {
189  std::ostringstream out;
190 
191  // Output opening tag.
192  if (_meta.has_model())
193  {
194  if (_meta.model().file_format().name() != "sdf")
195  {
196  std::cerr << "Model _metadata does not contain an SDF file.\n";
197  return false;
198  }
199 
200  out << "<?xml version='1.0'?>\n"
201  << " <model>\n"
202  << " <sdf version='"
203  << _meta.model().file_format().version().major()
204  << "." << _meta.model().file_format().version().minor() << "'>"
205  << _meta.model().file() << "</sdf>\n";
206  }
207  else
208  {
209  if (_meta.world().file_format().name() != "sdf")
210  {
211  std::cerr << "World _metadata does not contain an SDF file.\n";
212  return false;
213  }
214 
215  out << "<?xml version='1.0'?>\n"
216  << " <world>\n"
217  << " <sdf version='"
218  << _meta.world().file_format().version().major()
219  << "." << _meta.world().file_format().version().minor() << "'>"
220  << _meta.world().file() << "</sdf>\n";
221  }
222 
223  out << " <name>" << _meta.name() << "</name>\n"
224  << " <version>" << _meta.version() << "</version>\n"
225  << " <description>" << _meta.description() << "</description>\n";
226 
227  // Output author information.
228  for (int i = 0; i < _meta.authors_size(); ++i)
229  {
230  out << " <author>\n"
231  << " <name>" << _meta.authors(i).name() << "</name>\n"
232  << " <email>" << _meta.authors(i).email() << "</email>\n"
233  << " </author>\n";
234  }
235 
236  // Output dependency information.
237  for (int i = 0; i < _meta.dependencies_size(); ++i)
238  {
239  out << " <depend>\n"
240  << " <model>\n"
241  << " <uri>" << _meta.dependencies(i).uri() << "</uri>\n"
242  << " </model>\n"
243  << " </depend>\n";
244  }
245 
246  // Output closing tag.
247  if (_meta.has_model())
248  out << " </model>\n";
249  else
250  out << " </world>\n";
251 
252  _modelConfigStr = out.str();
253  return true;
254 }
255 } // namespce
256 } // namespace gz::msgs
257 
258 #endif // GZ_MSGS_CONVERT_FUELMETADATA_HH_